/** ==================================================================================== **/
/** 			Definizione della direttiva "Mappa anagrafica entita" ...			     **/
/** ==================================================================================== **/

/**
 * USO:
 *  È necessario includere nella pagina, in cui si vuole rendere disponibile la mappa per la geolocalizzazione di un elemento, 
 *  la seguente direttiva:
 *  
 *   (code)
 *   	<widget-map-ang 
 *   			is-required="..." valid-on-submit="..." ng-model="..." [validate-geometry] api="..." end-render="..." config="...">
 *   	</widget-map-ang>
 *   (code)
 *   
 * COSA FA:
 *   La direttiva crea il widget per la geolocalizzazione di un'entità. Il widget è costituito dai seguenti componenti:
 *     1. mappa
 *	   2. geolocalizzazione su mappa di un indirizzo e/o di una coppia di coordinate
 *     3. posibilità di localizzare l'entità fornendo la geometria della stessa nel formato Wkt e/o GeoJson
 *   
 *  Gli attributi necessari alla direttiva sono:
 *  
 *     ATTRIBUTO  |  TYPE 	| REQUIRED |  DESCRIZIONE
 *---------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
 *  isRequired	  | Boolean |    NO    | Abilita la validazione della geometria come required. Predefinito false.
 *  validOnSubmit | Boolean |    NO	   | True o false se il messaggio di validazione deve essere mostrato solo dopo la sottomissione del form. Predefinito false.
 *    			  |		    |          | Se presente e la mappa è disegnata in un wizard deve essere valorizzata con "submittedWizard" -->> valid-on-submit="submittedWizard"
 *  ngModel		  | Object  |	 NO	   | Valorizzato dalla direttiva a true o false se la geometria è valida o meno, utile se l'errore deve essere
 *    			  |         |          | mostrato anche in un punto esterno alla direttiva.
 *  api			  | Object  |    --    | Valorizzato dalla direttiva con le funzioni invocabili
 *  endRender	  | Boolean |    --    | Valorizzata a true solo quando la mappa è pronta, da questo momento è possibile richiamare i servizi esposti
 * 				  |		    |          | dalla direttiva e interagire con la mappa.
 *  config		  | Object  |	 SI	   | Opzioni di configurazione del widget
 *   
 *   
 *  L'attributo "config" è un oggetto composto dalle seguenti proprietà:
 *  
 *      ATTRIBUTO    |  TYPE   | REQUIRED |  DESCRIZIONE
 *----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 *  editToolbar		 | Object  |    SI	  | Configurazione toolbar edit su mappa
 * hasCercaIndirizzo | Boolean |    NO	  | True o false a seconda se deve essere attivo la parte del componente che cerca l'indirizzo(geocoder). Predefinito false.
 * hasCercaLonlat    | Boolean |    NO    | True o false a seconda se deve essere attivo la parte del componente che localizza su mappa la coppia di coordinate. Predefinito false.
 *  treeConfig 		 | Object  |	SI	  | Opzioni di configurazione del widget dei layer.
 *     zoom		 	 | Integer |    SI    | Zoom al quale portare la mappa per visualizzare la geometria dell'entità 
 *   
 *   
 *  L'attributo "editToolbar" è un oggetto composto dalle seguenti proprietà:
 *  
 *    ATTRIBUTO  |   TYPE   | REQUIRED |  DESCRIZIONE
 *--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 *    enable	 | Boolean  |  	 SI    | Abilita la gestione dell'edit sulla mappa
 *   editOption	 |  Object  | 	 SI	   | Configurazione per la customizzazione della mappa quando l'edit è attivo.
 *   hasGeoJson	 | Boolean  |    NO    | True o false a seconda se deve essere attivo la parte del componente che disegna su mappa la geometria a partire dal geojson digitato. Predefinito false.
 *    hasWkt	 | Boolean  |    NO    | True o false a seconda se deve essere attivo la parte del componente che disegna su mappa la geometria a partire dal wkt digitato. Predefinito false.
 *  geometryType | String[] |    SI    | Le tipologie di geometrie che possono rappresentare l'entità.
 *     multi	 | Boolean  |    NO	   | Un valore booleano che determina se il comportamento di default dovrebbe permettere il disegno di una 
 *     			 |			|		   | singola feature alla volta o di più feature. 
 *     			 |			|		   | Se l'opzione è attiva, la proprietà "geometryType" deve prevedere in elenco il corrispondente typedi tipo "Multi...".
 *     			 |			|		   | Il valore predefinito è false.
 *      
 *      
 *  L'attributo "editOption" è un oggetto composto dalle seguenti proprietà:
 *  
 *   ATTRIBUTO  |    TYPE   | REQUIRED |  DESCRIZIONE
 *-----------------------------------------------------------------------------------------------------------------------------------   
 *    minZoom 	|  Integer  |	 SI	   | Zoom minimo in cui l'edit della geometria è possibile.
 *    maxZoom 	|  Integer  |    SI	   | Zoom massimo in cui l'edit della geometria è possibile.
 *  
 *   
 *  L'attributo "treeConfig" è un oggetto composto dalle seguenti proprietà:
 *  
 *      ATTRIBUTO  	 |      TYPE 	  | REQUIRED |  DESCRIZIONE
 *----------------------------------------------------------------------------------------------------------------------------------- 
 *  hasEntityTree    |    Boolean 	  |    SI	 | True o false a seconda se deve essere attivo il componente con i layer delle anagrafiche filtrate e selezionate.
 *  				 |				  |			 |
 *  treeIcon_sel     | 	  String  	  |    NO    | Path dell'icona rappresentativa del layer che mostra l'anagrafica selezionata, è disegnata alla sinistra 
 *  				 |	      		  |			 | del check che attiva/disattiva la visibilita del layer stesso.
 *  				 |				  |			 |
 *  layerName		 |     String  	  |    SI	 | Nome del layer dell'anagrafica, necessario per la definizione dello stile. L'elenco dei nome layer 
 *  				 |				  |			 | è definito nel file delle constanti(StyleConstants.js) col nome "Constants.layersName".
 *  				 |				  |			 |
 *  stylesel_m		 | ol.style.Style |    NO	 | Stile delle feature selezionata, quella relativa l'anagrafica in modifica o visualizzazione
 *  				 |				  |			 |
 *  templatePopup	 |     String     |    SI	 | Alla selezione della feature viene aperta una popup dove sono mostrate le informazioni dell'anagrafica.
 *					 |				  |			 | La presentazione e le informazioni da mostrare sono determinate dal template che fornite al widget.
 *					 |				  |			 | Considerato che nel formato GeoJson i dati custom della feature sono scritti nella propeietà "properties",
 *					 |				  |			 | nel template l'accesso ai dati sarà "properties.<...>".
 *					 |				  |			 |					
 *					 |				  |			 |   Esempio:
 *					 |				  |			 | 		<li><strong>{{'header.label.id' | translate}}</strong> {{properties.id}}</li>
 *					 |				  | 		 | 		<li><strong>{{'header.label.nome' | translate}}</strong> {{properties.nome}}</li>
 *					 |				  |			 | 
 *					 |				  |          | NOTA: Il template deve essero solo un elenco informazioni senza nessun bottone che esegue qualche azione.
 *  				 |				  |			 |
 * broadcastFunction |    Function    |    SI    | Funzione che la direttiva deve lanciare per segnalare al gestore della funzionalità, che è cambiata l'anagrafica selezionata.
 *    				 |				  |			 | In ingresso alla funzione, la direttiva fornisce automaticamnte il contenuto dell' "attributo" properties della vostra 
 *    				 |				  |			 | feature.
 *    				 | 				  |			 | 	Esempio:
 *    				 |				  |			 |       broadcastFunction: function(properties){
 *   				 | 				  |			 |			console.log("prova broadcast " + properties.id);
 *    				 |				  |			 |		 }
 *  				 |				  |			 |
 *   requestData	 |	  Object	  |	   SI 	 | Oggetto valorizzato con i dati con cui filtrare la ricerca.
 *  				 |				  |			 |
 *	 url			 |	  String	  |    SI	 | Url del servizio di ricerca 
 *  				 |				  |			 |
 *	 excludeFeature  |	  String[]    |    NO    | La proprietà serve a determinare quale feature eliminare dalla lista ritornata dal servizio descritto sopra.
 * 					 |				  |		  	 | La feature da eliminare dalla lista dovrebbe essere proprio quella selezionata.
 * 					 |	  			  |			 | L'eliminazione viene effettuata in base alla chiave di attributo data impostato al valore dato. 
 * 					 |	  			  |			 | Alla posizione zero dell'array va indicato il nome della proprietà da matchare, mentre alla posizione due il valore 
 * 					 |	  			  |			 |   Example: ["id", 48].
 *  				 |				  |			 |
 * 					 |				  | 		 | NOTA: "excludeFeature" è un parametro opzionale solo se nell'elenco ritornato dal servizio non dovesse esserci già la 
 * 					 |				  |		     |       feature dell'anagrafica selezionata.
 * onSelectNewElement|    Function    |    NO    | Funzione richiamata alla fine del draw di un nuovo oggetto e passa due parametri: wkt e coordinate  
 *  				 |				  |			 |
 *enableStrategyBbox |    Boolean     |    NO	 | Determina la strategy di caricamento da usare per il layer vector che accoglie le fetaures risultanti 
 * 					 |			 	  |			 | dalla ricerca. 
 * 					 |			 	  |			 | Il valore predefinito è False, il layer è configurato con strategy "ol.loadingstrategy.all", ciò 
 * 					 |			 	  | 		 | significa che carica tutte le features contemporaneamente in una sola chiamata.
 * 					 |			 	  |			 | Al contrario, il layer è configurato con strategy "ol.loadingstrategy.bbox", ciò significa che carica
 * 					 | 		 		  |  		 | le features sulla base dell'estensione della view della mappa. 
 * 					 | 		 		  |			 | Tale valore viene fornito al server nel parametro "envelope", il quale è del seguente tipo: 
 * 				     |			 	  |		     | 	Object{
 * 				     |			 	  |			 | 		double minx, the minimum x-coordinate
 * 				     |			 	  |			 |   	double maxx, the maximum x-coordinate
 * 				     |			 	  |			 |   	double miny, the minimum y-coordinate
 * 				     |			 	  |			 | 		double max, the maximum y-coordinate
 * 				     |			 	  |			 | 	}
 * 					 |			      |			 | Quando la view cambia, la chiamata al server cosi come è configurata viene ripetuta fornendo un nuovo
 * 					 |			      | 		 | valore per il parametro di request "envelope".
 *  				 |				  |			 |
 *  
 *  
 * NOTA:
 *  Dell' oggetto "treeConfig" le proprietà indicate come obbligatorie sono tali solo se la proprietà "hasEntityTree" è valorizzata a true.
 *  Se la proprietà "isRequired" è true ma "validOnSubmit" non è presente il messaggio di validazione viene mostrato sin da subito.
 *  Il servizio di ricerca deve essere una POST, la risposta del servizio deve essere l'oggetto @link ResponseData, la lista di elementi deve
 *  essere nel fomato GeoJson quindi una @link FeatureCollection.
 *  Il widget ha un sistema interno di gestione del loading.
 *    
 *  La direttiva mette a disposizione le seguenti funzioni accessibili da un controller esterno:
 *   1. "resetWidget": 		  Svuota la mappa da eventuali geometrie disegnate, disattiva tutti i controlli e svuota i campi dei diversi tool
 *   2. "geometryAsWkt": 	  Restituisce il WKT della geometria disegnata, altrimenti ritorna null.
 *   3. "geometryAsGeom": 	  Restituisce la geometry della geometria disegnata, altrimenti ritorna null.
 *   4. "enableWidget": 	  Abilita gli strumenti di edit della mappa e i vari tool di modo che la mappa sia editabile.
 *   5. "disableWidget": 	  Disabilita gli strumenti di edit della mappa e i vari tool di modo che la mappa sia navigabile in sola lettura.
 *   6. "addGeometryAsWkt":   Aggiunge alla mappa la feature costruita a partire dal WKT della geometria fornito come parametro.
 *							  Questa funzione serve a visualizzare su mappa l'entità qualora si conosca già la gemetria(Es: caso di dettaglio entità)
 *   7. "updateSize": 		  Forza il ricalcolo della dimensione della mappa. Questo dovrebbe essere chiamato quando il codice di terze parti cambia la 
 *   				  		  dimensione della finestra in cui è disegnata la mappa.
 *   8. "setHeaderAddress":   Aggiunge nella parte centrale della toolbar l'indirizzo che localizza la geometria. (SOLA LETTURA)
 *   						  Parametri:
 *   							1. indirizzo, 2. comune, 3. provincia(sigla)
 *   9. "clearHeaderAddress": Rimuove dalla toolbar la visualizzazione dell'indirizzo che localizza la geometria.
 *   
 * NOTA:
 *  Le funzioni "geometryAsWkt" e "geometryAsGeom" nel restituire la geometria disegnata tengono conto se l'opzione "multi" è attiva o meno.
 *  Nel dettaglio:
 * 	 1. opzione "multi" non attiva: ritorna la geometria singola nel type in cui è stata disegnata.
 * 	 3. opzione "multi" attiva: compongo la geometry Multi... integrando insieme le geometrie delle singole feature disegnate.
 *
 */
BootApplication.directive('widgetMapAng',
	["configuration", "olMapsInst", "olBuildService", "olControlService", "olInteractionService", "olLayerService", "olFormatService", 
	 "ngeoToolActivateMgr", "ngeoDecorateInteraction", "$translate", "olStyleService", "DialogService", "olFeatureService", "log", "$http",
	 "ngeoDecorateLayer", "$compile", "GeocoderOptions", "GeocoderService", "TemplateStyles", "olAttributeService", "$timeout",
    function(appConstants, olMapsInst, olBuildService, olControlService, olInteractionService, olLayerService, olFormatService, 
    		 ngeoToolActivateMgr, ngeoDecorateInteraction, $translate, olStyleService, DialogService, olFeatureService, log, $http,
    		 ngeoDecorateLayer, $compile, GeocoderOptions, GeocoderService, TemplateStyles, olAttributeService, $timeout) {
			
 return {
	restrict: 'EA',
	templateUrl: appConstants.getParam("Constants").ContextPath + "page/template/mappa/WidgetMappaAngDirective.jsp",
	replace: true,
	scope: {
		 isRequired: "=isRequired",
		 validOnSubmit: "=?",
		 ngModel: "=?",
		 api: "=",
		 endRender: "=endRender",
		 config: "=config"
	},
	link: function (scope, element, attrs) {
	
 /** ======================================================================================== **/
 /*  									RESET WIDGET FUNCTION								   */
 /** ======================================================================================== **/
		
		/**
		 * Eliminazione geometria disegnata e disattivazione dei controlli
		 * 
		 * @param {@link Boolean} centerMap, centra la mappa dopo averla resettata
		 */
		scope.resetMappa = function (centerMap) {
			/* Svuoto il layer dall'ultima feature disegnata. */
			if( scope.vector != null ) 				scope.vector.getSource().clear(true);
			/* Elimino le feature eventualmente selezionate. */
			if( scope.selectInteraction != null ) 	scope.selectInteraction.getFeatures().clear(true);
  				
			/* disattivo i controlli **/
			if(scope.drawPointInteraction != undefined)   scope.drawPointInteraction.active = false;
			if(scope.drawLineInteraction != undefined)    scope.drawLineInteraction.active = false;
			if(scope.drawPolygonInteraction != undefined) scope.drawPolygonInteraction.active = false;
			if(scope.drawCircleInteraction != undefined)  scope.drawCircleInteraction.active = false;
  				
			scope.selectInteraction.active = false;
			
			/* rimuovo le interaction per l'edit dalla mappa **/
			scope.olMapAng.removeInteraction(scope.modifyInteraction);
			scope.olMapAng.removeInteraction(scope.selectInteraction);
			
			/* Disattivo l'evento. */
			scope.olMapAng.un('pointermove', pointerMoveHandler);
			/* Remove help tooltip */
	      	scope.removeHelpTooltip();
	      	/* unset sketch **/
	      	scope.ngSketchFeature = null;

	      	/* Abilito i button di edit della toolbar */
	      	scope.isDisableEditToolbar = false;
	      	
	      	/* Disabilito il button di "Undo" per Rimuovere l'ultimo punto della della feature disegnata */
	      	scope.isDisableUndo = true;
	      	
	      	/* ricentro la mappa se è attiva l'opzione */
	      	if(centerMap){
	      		/* posiziono la mappa sulle coordinate del centro */
	      		scope.olMapAng.getView().setCenter(olFormatService.olProjTransorm(
	      			scope.olMapAng.getOptions().getCenter()[0], scope.olMapAng.getOptions().getCenter()[1], scope.olMapAng.getOptions().getSourceProjection(), scope.olMapAng.getOptions().getDestProjection()));
				
		      	/* porto la mappa allo zoom iniziale */
		      	scope.olMapAng.getView().setZoom(scope.olMapAng.getOptions().getZoom());
	      	}
	      	/* refresh mappa **/
	      	scope.onResize();
	    }// close resetMappa
	    	
		/**
		 * Reset del componente per la ricerca indirizzo.
		 */
		scope.resetGeocoder = function () {
			/* svuoto il campo di ricerca **/
			scope.geocoder.indirizzo = "";
	  			    	    
			/* elimina il marker dalla mappa */
			if(scope.layGeocoder != undefined && scope.layGeocoder != null) scope.layGeocoder.getSource().clear(true);
			
			/* spengo il loading dell'autocomplete */
			scope.geocoder.loadingLocations = false;
			/* nascondo il DIV del messaggio "no results" */
			scope.geocoder.noResults = false;
		}// close resetGeocoder
  	  
		/**
		 * Reset del componente per la geolocalizzazione su mappa di un indirizzo e/o di una coppia di coordinate, del componente per disegnare 
		 * su mappa una geometria dal formato Wkt e/o GeoJson 
		 */
		scope.resetTool = function () {
			/* Se non attivo almeno uno dei widget, nascondo il componente */
			if(!scope.config.hasCercaIndirizzo && !scope.config.hasCercaLonlat) scope.ngShowWidgetZoom = false;
			
			/* Se non attivo almeno uno dei widget, nascondo il componente */
			if(!scope.config.editToolbar.enable || (!scope.config.editToolbar.hasWkt && !scope.config.editToolbar.hasGeoJson)) scope.ngShowWidgetDraw = false;
	  		
			/* Se attivo, reset del componente del geocoding */
			if(scope.config.hasCercaIndirizzo) scope.resetGeocoder();
	    		
			/* 
			 * Se attivo, reset del componente "cerca coppia di coordinate" 
			 */
			if(scope.config.hasCercaLonlat){
				/* Gestione reset campo localizza punto dati lon/lat */
		    	scope.clearGeoLonLat();
	    	}
	    		
	    	/* 
	    	 * Se attivo, reset del componente che disegna la geometria a partire dalla stringa WKT 
	    	 */
	    	if (scope.config.editToolbar.enable && scope.config.editToolbar.hasWkt) {
	    		/* svuoto il campo di ricerca **/
	    		scope.format.formatWktDraw = "";
	    		/* chiudo il popup di help **/
	    		scope.wktPopover.isOpen = false;
	    	}
	    	
	    	/* 
	    	 * Se attivo, reset del componente che disegna la geometria a partire dal strina GeoJson 
	    	 */
	    	if (scope.config.editToolbar.enable && scope.config.editToolbar.hasGeoJson) {
	    		/* svuoto il campo di ricerca **/
	    		scope.format.formatGeoJsonDraw = "";
	    		/* chiudo il popup di help **/
	    		scope.geojsonPopover.isOpen = false;
	    	}
	    		
	    	/* 
	    	 * Se attivo, reset del componente dell' albero 
	    	 */
	    	if(scope.config.treeConfig.hasEntityTree){
	    		/* hide the popup. */
			    scope.closePopup();
			    /* Svuoto il layer dall'ultima feature disegnata. */
			    scope.vectorEntity.getSource().clear(true);
			    /* Elimino le feature eventualmente selezionate. */
			    if( scope.highlightsEntityInteraction != null ) scope.highlightsEntityInteraction.getFeatures().clear(true);
			    /* Elimino le feature eventualmente selezionate. */
			    if( scope.selectEntityInteraction != null ) 	scope.selectEntityInteraction.getFeatures().clear(true);
	    	}
	    }// close resetTool
	    	
		/**
		 * Svuota la mappa da eventuali geometrie disegnate, disattiva tutti i controlli e svuota i campi dei diversi tool
		 */
		scope.resetWidget = function (){
			/*
			 * Eliminazione geometria disegnata e disattivazione dei controlli
			 */
			scope.resetMappa(true);
			/*
			 * Reset del componente per la geolocalizzazione su mappa di un indirizzo e/o di una coppia di coordinate, del componente per disegnare 
			 * su mappa una geometria dal formato Wkt e/o GeoJson 
			 */
			scope.resetTool();
			/*
	    	 * Rimuove dalla toolbar la visualizzazione dell'indirizzo che localizza la geometria.
	    	 */
			scope.headerAddress = {visible: false};
	    }// close resetWidget
	    	
 /** ======================================================================================== **/
 /*  											RESIZE MAPPA								   */
 /** ======================================================================================== **/
	    		    	   
	    /**
	     * Forza il ricalcolo della dimensione della mappa
	     */
		scope.onResize = function (){
			scope.olMapAng.updateSize();
			scope.olMapAng.render();
		}
		/**
		 * Gestione evento di resize del DIV della direttiva
		 */
		scope.$watch( function() {
			scope.__width = element.width();
	    });
		scope.$watch('__width', function( newHeight, oldHeight ) {
			scope.onResize();
	    });
		/**
		 * Gestione evento di resize della finestra del browser
		 */
		$(window).bind('resize', function(){
			scope.onResize();
	    });
	    	
 /** ======================================================================================== **/
 /*  									EVENTI INTERACTION MAPPA							   */
 /** ======================================================================================== **/
	    		    	
		/** 
		 * Funzione richiamata quando viene lanciato l'evento di "drawstart". Viene cancellata l'ultima feature eventualmente
		 * disegnata dalla mappa e dall'attributo della direttiva. 
		 */
		scope.drawStart_ = function (e){
			/* set sketch per l'help tooltip **/
			scope.ngSketchFeature = e.feature;
			
	    	/* Se l'opzione "multi" è attiva, quando inizio a disegnare svuoto il layer dall'ultima feature disegnata. */
			if( !scope.config.editToolbar.multi && scope.vector != null ) scope.vector.getSource().clear(true);
			/* Quando inizio a disegnare elimino le feature eventualmente selezionate. */
			if( scope.selectInteraction != null ) scope.selectInteraction.getFeatures().clear(true);
  				
			/* rimuovo le interaction per l'edit dalla mappa **/
			scope.olMapAng.removeInteraction(scope.modifyInteraction);
			scope.olMapAng.removeInteraction(scope.selectInteraction);
  				
			/* Abilito il button di "Undo" per Rimuovere l'ultimo punto della della feature disegnata */
			scope.isDisableUndo = false;
			
			/* refresh mappa **/
			scope.onResize();
	    }// close drawStart_
		
		/** 
		 * Funzione richiamata quando viene lanciato l'evento di "drawend", l'evento è intercettato prima che la feature
		 * venga inserita al layer.
		 * 
		 * @param {@link ol.interaction.DrawEvent} e
		 */
		scope.drawEnd_ = function (e){
			
			if(scope.config.treeConfig.onSelectNewElement){
				try{
					
					var temp = e.feature.clone();
					var geometry = temp.getGeometry().transform(appConstants.getParam("Constants").DEST_PROJECTION, appConstants.getParam("Constants").SOURCE_PROJECTION);
					if (geometry instanceof ol.geom.Circle) geometry = ol.geom.Polygon.fromCircle(geometry);
					var wkt = olFormatService.olWktTransorm(geometry);
					
					scope.config.treeConfig.onSelectNewElement(wkt, geometry.getCoordinates());
				}catch(e){
					log.error("Error in onSelectNewElement");
					log.error(e);
				}
				
				
			}
			
			/* unset sketch **/
			scope.ngSketchFeature = null;
			
			/* Disabilito il button di "Undo" per Rimuovere l'ultimo punto della della feature disegnata */
			scope.isDisableUndo = true;
	    }//
	    	
		/* Triggered upon feature draw start **/
		if(scope.drawPointInteraction != undefined)   scope.drawPointInteraction.on('drawstart', function (e) { scope.drawStart_(e); });
		if(scope.drawLineInteraction != undefined)    scope.drawLineInteraction.on('drawstart', function (e) { scope.drawStart_(e); });
		if(scope.drawPolygonInteraction != undefined) scope.drawPolygonInteraction.on('drawstart', function (e) { scope.drawStart_(e); });
		if(scope.drawCircleInteraction != undefined)  scope.drawCircleInteraction.on('drawstart', function (e) { scope.drawStart_(e); });
		
		/* Triggered upon feature draw end **/
		if(scope.drawPointInteraction != undefined)   scope.drawPointInteraction.on('drawend', function (e) { scope.drawEnd_(e); });
		if(scope.drawLineInteraction != undefined)    scope.drawLineInteraction.on('drawend', function (e) { scope.drawEnd_(e); });
		if(scope.drawPolygonInteraction != undefined) scope.drawPolygonInteraction.on('drawend', function (e) { scope.drawEnd_(e); });
		if(scope.drawCircleInteraction != undefined)  scope.drawCircleInteraction.on('drawend', function (e) { scope.drawEnd_(e); });
		
		/**
		 * Disattiva la possibilità di selezionare, per vedere la popup, le feature della ricerca
		 */
		scope.disableEntityInteraction = function (){
			if(scope.config.treeConfig.hasEntityTree){
    			/* hide the popup. */
				scope.closePopup();
    		    /*  */
				if( scope.selectEntityInteraction != null ) {
					/* Elimino le feature eventualmente selezionate. */
					scope.selectEntityInteraction.getFeatures().clear(true);
					/* Disactive interaction select */
					scope.selectEntityInteraction.setActive(false);
				}
			}
		}
		/**
		 * Attiva la possibilità di selezionare le feature della ricerca, per vedere la popup
		 */
		scope.enableEntityInteraction = function (){
			/*  */
			if(scope.config.treeConfig.hasEntityTree) {
				/* Re-active interaction select */
				if( scope.selectEntityInteraction != null ) scope.selectEntityInteraction.setActive(true);
			}
		}
		
 /** ======================================================================================== **/
 /*  										  TOOLTIP MAPPA									   */
 /** ======================================================================================== **/
	    
		/**
		 * Handle pointer move.
		 * @param {ol.MapBrowserEvent} evt
		 */
		var pointerMoveHandler = function(evt) {
			if (evt.dragging) return;
			
			/* @type {string} */
			var helpMsg = scope.startMsg;
			/* @type {ol.Coordinate|undefined} */
			var tooltipCoord = evt.coordinate;

			if (scope.ngSketchFeature) {
				/* caso in cui è già stato diseganto un punto in mappa **/
				var geom = scope.ngSketchFeature.getGeometry();
				
				if (geom instanceof ol.geom.LineString) helpMsg = scope.continueLinestringMsg;
				if (geom instanceof ol.geom.Polygon) 	helpMsg = scope.continuePolygonMsg;
				if (geom instanceof ol.geom.Circle) 	helpMsg = scope.continueCircleMsg;
	    	}
	    		
			scope.helpTooltipElement.innerHTML = helpMsg;
			scope.helpTooltip.setPosition(tooltipCoord);
    	};		    		
    	/**
    	 * Creates a new help tooltip
    	 */
    	scope.createHelpTooltip = function() {
    		/* se gia c'è rimuovo gli elementi html **/
    		if (scope.helpTooltipElement) scope.helpTooltipElement.parentNode.removeChild(scope.helpTooltipElement);
    		
    		/* creo il DIV per il tooltip **/
    		scope.helpTooltipElement = document.createElement('div');
    		scope.helpTooltipElement.className = 'tooltip';
    		
    		/* 
    		 * Overlay per mostrare l'help messages.
    		 * NOTA "Overlay":
    		 *   Un elemento da visualizzare sulla mappa e collegata a una singola posizione sulla mappa.
    		 *   Come ol.control.Control, overlay sono i widget visibili. A differenza dei controlli, non sono in una posizione fissa 
    		 *   sullo schermo, ma sono legati a delle coordinate geografiche.
    		 */
    		scope.helpTooltip = new ol.Overlay({
    			element: scope.helpTooltipElement,
    			offset: [15, 0],
    			positioning: 'center-left'
    		});
    			
    		scope.olMapAng.addOverlay(scope.helpTooltip);
    	}// close createHelpTooltip
    	
    	/**
    	 * Remove help tooltip
    	 */
    	scope.removeHelpTooltip = function() {
    		/* Rimuovere l'overlay dell'help message dalla mappa. **/
    		scope.olMapAng.removeOverlay(scope.helpTooltip);
    		
    		if (scope.helpTooltipElement !== null) scope.helpTooltipElement.parentNode.removeChild(scope.helpTooltipElement);
    			
    		/* unset help element **/
    		scope.helpTooltipElement = null;
    		scope.helpTooltip = null;
    		/* unset sketch **/
    		scope.ngSketchFeature = null;
    		/* Disattivo l'evento. */
        	scope.olMapAng.un('pointermove', pointerMoveHandler );
    	}// close removeHelpTooltip
    	
 /** ======================================================================================== **/
 /*  									GESTIONE CONTROLLO ZOOM EDIT 						   */
 /** ======================================================================================== **/
    	 
    	/**
    	 * Controllo se l'edit su mappa è attivo, in tal caso ativvo uno watch sulla proprietà che individua se gli strumenti di 
    	 * edit sono disabilitati o meno.
    	 */
    	if(scope.config.editToolbar.enable){
    		/* 
    		 * Sono nel caso in la direttiva è compilata per la prima volta, controllo se la toolbar è abilitata di modo da determinare se
    		 * per lo zoom corrente gli strumenti di edit sono selezionabili o meno.
    		 */ 
			if(!scope.isDisableEditToolbar){
				
				if(scope.olMapAng.getView().getZoom() < scope.config.editToolbar.editOption.minZoom)
				   /* L'utente è un livello di zoom non ammesso per l'edit, per cui li disabilito di modo che non sono selezionabili */
				   scope.isDisableEditZoom = true;
				else
				   /* L'utente è un livello di zoom ammesso per l'edit, per cui li abilito di modo che sono selezionabili */
				   scope.isDisableEditZoom = false;
			}// 
			
			/* 
    		 * In seguito al controllo precedente attivo un watch sulla proprietà "isDisableEditToolbar" cosi da gestire il caso dello 
    		 * zoom relativo gli strumenti di edit ogni qualvolta la mappa è disabilitata o meno.
    		 */ 
			scope.$watch('isDisableEditToolbar', function(value) {
				/* 
	    		 * Sono nel caso è cambiato il valore di 'isDisableEditToolbar', controllo se la toolbar è abilitata di modo da determinare se
	    		 * per lo zoom corrente gli strumenti di edit sono selezionabili o meno.
	    		 */ 
    			if(!scope.isDisableEditToolbar){
    				
	    			if(scope.olMapAng.getView().getZoom() < scope.config.editToolbar.editOption.minZoom)
	    			   /* L'utente è un livello di zoom non ammesso per l'edit, per cui li disabilito di modo che non sono selezionabili */
	    			   scope.isDisableEditZoom = true;
	    			else
	    			   /* L'utente è un livello di zoom ammesso per l'edit, per cui li abilito di modo che sono selezionabili */
	    			   scope.isDisableEditZoom = false;
    			}else
    				/* Toolbar resa disabled, disabilito per coerenza anche gli strumenti di edit */
    				scope.isDisableEditZoom = true;
    			
    			return false;
    		});
			
			/**
	    	 * Funzione che registra alla mappa l'evento che viene lanciato quando lo zoom della mappa cambia.
	    	 */
	    	scope.eventKey = scope.olMapAng.getView().on('change:resolution',function(e){
	    		/* 
	    		 * Sono nel caso è cambiato lo zoom della mappa, controllo se la toolbar è abilitata di modo da determinare se
	    		 * per lo zoom corrente gli strumenti di edit sono selezionabili o meno.
	    		 */ 
	    		if(!scope.isDisableEditToolbar){
		    	
	    			if(scope.olMapAng.getView().getZoom() < scope.config.editToolbar.editOption.minZoom){
	        			/* La toolbar è abilita ma, l'utente è un livello di zoom non ammesso per l'edit, per cui li disabilito di modo che non sono selezionabili */
	    				scope.isDisableEditZoom = true;
	        				
	    				/*
	    				 * Inoltre se è attivo uno degli strumenti di edit, informo l'utente tramite popup, che l'edit non è possibile ad uno zoom inferiore.
	    				 */
	    				if((scope.drawPointInteraction != undefined && scope.drawPointInteraction.active) || 
	    						(scope.drawLineInteraction != undefined && scope.drawLineInteraction.active) || 
	    						(scope.drawPolygonInteraction != undefined && scope.drawPolygonInteraction.active) || 
	    						(scope.drawCircleInteraction != undefined && scope.drawCircleInteraction.active) ||
	    						(scope.selectInteraction != undefined && scope.selectInteraction.active)){
	    					
		        			/* riporto il current zoom ad un livello concesso per l'edit */
	    					scope.olMapAng.getView().setZoom(scope.config.editToolbar.editOption.minZoom);
	    					/* apro la popup informativa */
	    					scope.infoPopupZoomEdit();
	        			}
	        		}else
	        		   /* L'utente è un livello di zoom ammesso per l'edit, per cui li abilito di modo che sono selezionabili */
	        		   scope.isDisableEditZoom = false;
	    		}else{
	    		   /* Toolbar resa disabled, disabilito per coerenza anche gli strumenti di edit */
	    		   scope.isDisableEditZoom = true;
	    		}
	    		return false;
	    	});
	    	
	    	/**
			 * Apro la popup per informare l'utente che l'edit è possibile solo a zoom superiori.
			 * @export
			 */
	    	scope.infoPopupZoomEdit = function (){
	    		/* mostro l'alert */
	    		scope.shAlertZoomEdit = true;
	    		
	    		$timeout(function(){
	    			/* lo nascondo */
	        		scope.shAlertZoomEdit = false;
	    		}, 2000);
	    	}
	    	
	    	/**
	    	 * Removes an event listener using the key returned by on().
	    	 */
	    	scope.unRegisterEventChZoom = function (){
	    		if(angular.isDefined(scope.eventKey) && scope.eventKey != null) {
	    			scope.olMapAng.getView().unByKey(scope.eventKey);
	    			delete scope.eventKey;
	    		}
	    	}
    	}// close zoom edit control
    	
 /** ======================================================================================== **/
 /*  										CLICK CONTROL BUTTON							   */
 /** ======================================================================================== **/
    		    	
    	/** 
    	 * Funzione richiamata al click del control button (Draw point).
    	 */
    	scope.ngClickPointControl = function (){
    		/* Remove help tooltip */
    		scope.removeHelpTooltip();
    		
    		/* Controllo che l'opzione che disabilita gli stumenti di edit non sia attiva */
    		if(!scope.isDisableEditToolbar && !scope.isDisableEditZoom && scope.drawPointInteraction.active)
    	   	  /*
    		   * Disattiva la possibilità di selezionare, per vedere la popup, le feature della ricerca
    		   */
    		  scope.disableEntityInteraction();
	    	else{
	    	  /*
	    	   * Attiva la possibilità di selezionare, per vedere la popup, le feature della ricerca
	    	   */
	    	  scope.enableEntityInteraction();
	    	  
	    	  scope.drawPointInteraction.active = false;
	    	}
	    }// close ngClickPointControl
	    
    	/** 
    	 * Funzione richiamata al click del control button (Draw line).
    	 */
    	scope.ngClickLineControl = function (){
    		/* Remove help tooltip */
    		scope.removeHelpTooltip();
    		
    		/* Controllo che l'opzione che disabilita gli stumenti di edit non sia attiva */
    		if(!scope.isDisableEditToolbar && !scope.isDisableEditZoom && scope.drawLineInteraction.active){
    			
    			/* Attivato quando un puntatore viene spostato. */
    			scope.olMapAng.on('pointermove', pointerMoveHandler);
	    		/* Creates a new help tooltip */
	    		scope.createHelpTooltip();
	    		/* Disattiva la possibilità di selezionare, per vedere la popup, le feature della ricerca */
	    		scope.disableEntityInteraction();
    		}else{
    			/* Attiva la possibilità di selezionare, per vedere la popup, le feature della ricerca */
    			scope.enableEntityInteraction();
    			
    			scope.drawLineInteraction.active = false;
    		}
	    }// close ngClickLineControl
    	
    	/** 
    	 * Funzione richiamata al click del control button (Draw polygon).
    	 */
    	scope.ngClickPolygonControl = function (){
    		/* Remove help tooltip */
        	scope.removeHelpTooltip();
        	
    		/* Controllo che l'opzione che disabilita gli stumenti di edit non sia attiva */
    		if(!scope.isDisableEditToolbar && !scope.isDisableEditZoom && scope.drawPolygonInteraction.active){
    			/* Attivato quando un puntatore viene spostato. */
    			scope.olMapAng.on('pointermove', pointerMoveHandler);
    			/* Creates a new help tooltip */
    			scope.createHelpTooltip();
    			/* Disattiva la possibilità di selezionare, per vedere la popup, le feature della ricerca */
    			scope.disableEntityInteraction();
    		}else{
    			/* Attiva la possibilità di selezionare, per vedere la popup, le feature della ricerca */
    			scope.enableEntityInteraction();
    			
    			scope.drawPolygonInteraction.active = false;
		    }
	    }// close ngClickPolygonControl
	    
    	/** 
    	 * Funzione richiamata al click del control button (Circle polygon).
    	 */
	    scope.ngClickCircleControl = function (){
	    	/* Remove help tooltip */
	    	scope.removeHelpTooltip();
	    	
	    	/* Configura la mappa per l'edit */
    		if(!scope.isDisableEditToolbar && !scope.isDisableEditZoom && scope.drawCircleInteraction.active){
    			
		    	/* Attivato quando un puntatore viene spostato. */
		    	scope.olMapAng.on('pointermove', pointerMoveHandler );
		    	/* Creates a new help tooltip */
		    	scope.createHelpTooltip();
		    	/* Disattiva la possibilità di selezionare, per vedere la popup, le feature della ricerca */
		    	scope.disableEntityInteraction();
    		}else{
    			/* Attiva la possibilità di selezionare, per vedere la popup, le feature della ricerca */
    			scope.enableEntityInteraction();
    		
    			scope.drawCircleInteraction.active = false;
    		}
	    }// close ngClickCircleControl
	    
	    /** 
	     * Funzione richiamata al click del control button (Edit geometry).
	     */
	    scope.ngClickModifyControl = function (){
	    	/* Remove help tooltip */
	    	scope.removeHelpTooltip();
	    	
	    	/* Configura la mappa per l'edit */
    		if(!scope.isDisableEditToolbar && !scope.isDisableEditZoom && scope.selectInteraction.active){
    			
    			if(scope.vector != null){
    				/* mi prendo le features **/
    				var features = scope.vector.getSource().getFeatures();
		    			
    				/* controllo che ci sia una feature  **/
    				if(features != null && features.length != 0){
    					/* 
    					 * Una geometria di tipo ol.geom.Circle non è gestita dall'edit 
    					 * quindi se è questo il caso la trasformo in ol.geom.Polygon
    					 */
    					if (features[0].getGeometry() instanceof ol.geom.Circle)
    						features[0].setGeometry(ol.geom.Polygon.fromCircle(features[0].getGeometry()));
	    	  		}// close
	    	  	}// close
		    	
    			/* aggiungo le interaction per l'edit dalla mappa **/
    			scope.olMapAng.addInteraction(scope.selectInteraction);
    			scope.olMapAng.addInteraction(scope.modifyInteraction);
		    		
    			/* Disattiva la possibilità di selezionare, per vedere la popup, le feature della ricerca */
    			scope.disableEntityInteraction();
    		}else{
    			/* rimuovo le interaction per l'edit dalla mappa **/
    			scope.olMapAng.removeInteraction(scope.modifyInteraction);
    			scope.olMapAng.removeInteraction(scope.selectInteraction);
		      		
    			scope.selectInteraction.active = false; 
    			
    			/* Attiva la possibilità di selezionare, per vedere la popup, le feature della ricerca */
    			scope.enableEntityInteraction();
	        }
	    }// close ngClickModifyControl
	    
	    /** 
	     * Funzione richiamata al click del control button (Cancel geometry).
	     * 
	     * Comportamento della funzione:
	     * 	1. opzione "multi" non attiva: dal layer di edit vengono rimosse tutte le feature definitivamente.
	     * 	2. opzione "multi" attiva ma nessuna feature è selezionata: dal layer di edit vengono rimosse tutte le feature definitivamente.
	     * 	3. opzione "multi" attiva e vi è una feature selezionata: dal layer di edit viene rimossa definitivamente solo la feature selezionata.
	     */
	    scope.ngClickCancelControl = function (){
	    	/** 
	    	 * Controllo che l'opzione che disabilita gli stumenti di edit non sia attiva 
	    	 */
    		if(!scope.isDisableEditToolbar){
    			
    			if( scope.vector != null ) {
    				/** Caso SINGLE GEOMETRY, Svuoto il layer dall'ultima feature disegnata. */
    				if(!scope.config.editToolbar.multi || (scope.config.editToolbar.multi && (scope.selectInteraction == null || scope.selectInteraction.getFeatures().getLength() == 0)) ) 
    					/* 
    					 * Dal layer sono rimosse tutte le feature definitivamente
    					 */
    					scope.vector.getSource().clear(true);
    				else{
    					/** Caso MULTI GEOMETRY, elimino dal layer la feature selezionata. */
    					if( scope.selectInteraction != null && scope.selectInteraction.getFeatures().getLength() != 0 ) {
    						/* 
    						 * Recupero la feature selezionata 
    						 */
    						var selectedFea = scope.selectInteraction.getFeatures().item(0);
    						/*
    						 * Remove a single feature from the source.
    						 */
    						scope.vector.getSource().removeFeature(selectedFea);
    					}
    				}// close multi
    			}// close vector is null
    			
    			/* Elimino le feature eventualmente selezionate. */
    			if( scope.selectInteraction != null ) scope.selectInteraction.getFeatures().clear(true);
    			
    	      	/* Disabilito il button di "Undo" per Rimuovere l'ultimo punto della della feature disegnata */
    	      	scope.isDisableUndo = true;
    	      	
    	      	/* refresh mappa **/
    	      	scope.onResize();
			    
    	      	/* Versione updata il 30 Novembre
    	      	 * Eliminazione geometria disegnata e disattivazione dei controlli 
			   	 * scope.resetMappa(false);
		    	 */
    	      	
		  		/* Attiva la possibilità di selezionare, per vedere la popup, le feature della ricerca */
		       	scope.enableEntityInteraction();
    		}//
	    }//close ngClickCancelControl
	
	    /**
	     * Rimuovere l'ultimo punto della feature disegnata
	     */
	    scope.ngClickRemoveLastPoint = function(){
			if(scope.drawPointInteraction != undefined && scope.drawPointInteraction.active)     scope.drawPointInteraction.removeLastPoint();
			if(scope.drawLineInteraction != undefined && scope.drawLineInteraction.active)       scope.drawLineInteraction.removeLastPoint();
			if(scope.drawPolygonInteraction != undefined && scope.drawPolygonInteraction.active) scope.drawPolygonInteraction.removeLastPoint();
			if(scope.drawCircleInteraction != undefined && scope.drawCircleInteraction.active)   scope.drawCircleInteraction.removeLastPoint();
	    }// close
		
	    /**
	     * Sposta la visualizzazione della mappa, centrando e zommando, sulla geometria dell'anagrafica in modifica o inserimento.
	     */
	    scope.ngClickReCenterOn = function (){
	    	/* aggiungo la feature al layer **/
			if(scope.vector.getSource().getFeatures() != null && scope.vector.getSource().getFeatures().length != 0){
				/*
				 * Genero una transizione animata durante l'aggiornamento del centro della mappa.
				 */
				var pan = ol.animation.zoom({});
				/*
				 * Aggiungo l'animazione che deve essere richiamata prima del rendering(prima di aggiornare la visualizzazione della mappa). 
				 */
			    scope.olMapAng.beforeRender(pan);
			    
			    /* Ottenere l'estensione delle features. */
			    var extent = scope.vector.getSource().getExtent();
			    		
			    /* Adatta la forma geometrica data o misura in base alla data dimensione mappa e di confine. **/
			    scope.olMapAng.getView().fit(extent, scope.olMapAng.getSize(), {"maxZoom": scope.config.zoom});
			}
	    }// close ngClickReCenterOn
	    
 /** ======================================================================================== **/
 /*  							 FUNZIONI CERCA INDIRIZZO - LON/LAT 						   */
 /** ======================================================================================== **/
	   	    
		if(scope.config.hasCercaIndirizzo || scope.config.hasCercaLonlat) {
			/**
			 * Apertura/chiusura Widget per cercare l'indirizzo o le coordinate
			 */
			scope.changeShowZoomHelp = function (){
				/* nascondo il box dell'albero dei layer */
				scope.ngShowTreeEntity = false;
				/* nascondo il box per disegnare */
				scope.ngShowWidgetDraw = false;
				/* mostro/nascondo il box per zoom ad un indirizzo o a delle coordinate */
				scope.ngShowWidgetZoom = !scope.ngShowWidgetZoom;
			}
		}// close if hasCercaIndirizzo || hasCercaLonlat
		
		if(scope.config.editToolbar.enable && (scope.config.editToolbar.hasWkt || scope.config.editToolbar.hasGeoJson)) {
			/**
			 * Apertura/chiusura Widget per disegnare la geometria
			 */
			scope.changeShowDrawHelp = function (){
				/* Controllo che l'opzione che disabilita gli stumenti di edit non sia attiva */
	    		if(!scope.isDisableEditToolbar){
					/* nascondo il box per lo zoom */
					scope.ngShowWidgetZoom = false;
					/* nascondo il box dell'albero dei layer */
					scope.ngShowTreeEntity = false;
					/* mostro/nascondo il box per disegnare da wkt o geojson */
					scope.ngShowWidgetDraw = !scope.ngShowWidgetDraw;
				}
			}
		}// close if hasWkt || hasGeoJson
		
 /** ======================================================================================== **/
 /*  									 FUNZIONI CERCA INDIRIZZO 							   */
 /** ======================================================================================== **/
	   	
	    if(scope.config.hasCercaIndirizzo){
	    	/**
	    	 * Chiamata al servizio di Autocomplete 
	    	 */
	    	scope.getLocation = function(val) {
		    	/* filter geocoder **/
	    		var filter = new GeocoderOptions(null, scope.olMapAng.getOptions().getCenter());

	    		return GeocoderService.autocompletegeo(val, filter).then(function(response){
	    			return response;
	    		});
	    	}// close getLocation
	    	 
	    	/** 
	    	 * Funzione richiamata alla selezione di un'indirizzo ne legge le coordinate e disegna il marker che le localizza sulla mappa.
	    	 */
	    	scope.selectOnMatch = function ($item, $model, $label, $event){
	    		try{
		    		if($item.lon != null && $item.lat != null){
		    				
		    			/** Crea la feature che ha per geometria le coordinate digitate. **/
		    			var feature = olFeatureService.createFeaturePoint(
		    					/* lon / lat */
		    					parseFloat($item.lon), parseFloat($item.lat),
		    					/* id feature **/
		    					appConstants.getParam("ol.ApplicationProperty").ID_FEATURE_GEO_INDIRIZZO,
		    					/* descrittore dello stile del marker */
		    					null,
		    					/* projection */
		    					scope.olMapAng.getOptions().getSourceProjection(), scope.olMapAng.getOptions().getDestProjection());
						    			
				    	/** elimino dal layer le feature **/
		    			scope.layGeocoder.getSource().clear(true);
		    			/** aggiungo la feature al layer **/
		    			scope.layGeocoder.getSource().addFeature(feature);
		    			
		    			/**
		    			 * Genero una transizione animata durante l'aggiornamento del centro della mappa.
		    			 */
		    			var pan = ol.animation.pan({
		    				/** The duration of the animation in milliseconds. Default is 1000. **/
		    				duration: 2000,
		    				/** The location to start panning from, typically map.getView().getCenter(). **/
		    				source: scope.olMapAng.getView().getCenter()
		    			});
		    			/**
		    			 * Aggiungo l'animazione che deve essere richiamata prima del rendering(prima di aggiornare la visualizzazione della mappa). 
		    			 */
		    			scope.olMapAng.beforeRender(pan);
		    			
		    			/** Ottenere l'estensione delle features. */
		    			var extent = scope.layGeocoder.getSource().getExtent();
		    				
		    			/** Adatta la forma geometrica data o misura in base alla data dimensione mappa e di confine. **/
		    			scope.olMapAng.getView().fit(extent, scope.olMapAng.getSize(), {"maxZoom": 14});
		    				
		    			/**
		    			 * Forza il ricalcolo della dimensione della mappa
		    			 */
		    			scope.onResize();
		    		}// close lon e lat valid
		    		else
		    			log.warning("Ricerca indirizzo: Latitudine e longitudine non impostate correttamente");
	    		  
		    	}catch(e){
		    		log.error("selectOnMatch >> " + e);
		    	}
	    	}// close selectOnMatch
	    }// close if hasCercaIndirizzo
	    
 /** ======================================================================================== **/
 /*  									 FUNZIONI CERCA LON-LAT 							  */
 /** ======================================================================================== **/
	    		  
	    if(scope.config.hasCercaLonlat){
	    	/**
	    	 * Gestione reset campo localizza punto dati lon/lat
	    	 */
	    	scope.clearGeoLonLat = function () {
	    		/* remove error **/
    			scope.coordinate.showErrorGLonlat = false;
				scope.coordinate.messageGLonlat = "";
	    		
	    		/* svuoto il campo di lon **/
				scope.coordinate.geoLon = "";
				/* svuoto il campo di lat **/
				scope.coordinate.geoLat = "";
				/* Elimino le feature eventualmente aggiunte al layer del cerca lon/lat. */
				if( scope.layGeoLonlat != null ) scope.layGeoLonlat.getSource().clear();
		   	}// close clearGeoLonLat
		    	
	    	/** 
	    	 * Al click del button viene richiamata una funzione che legge le coordinate inserite
	    	 * e disegna il marker che le localizza sulla mappa .
	    	 */
	    	scope.localizzaGeoLonLat = function(){
	    		try{	 
	    			/* Mostra il loading */
	    			scope.isLoading = true;
	    			
	    			/* remove error **/
	    			scope.coordinate.showErrorGLonlat = false;
					scope.coordinate.messageGLonlat = "";
	    			
					/* Verifica campo obbligatorio */
					if(!angular.isDefined(scope.coordinate.geoLon) || scope.coordinate.geoLat == ""){
	    				/* Rimuove il loading */
	    				scope.isLoading = false;
	    				
	    				/* add error campo abbligatorio **/
	    				scope.coordinate.showErrorGLonlat = true;
	    				scope.coordinate.messageGLonlat = $translate.instant('Validator.requiredField');
	    				return ;
					}
					/* Verifica formato campo longitudine */
					if(!$.isNumeric(scope.coordinate.geoLon)){
		    			/** nascondo il loading */
						scope.isLoading = false;
						 
						/* add error formato non valido **/
	    				scope.coordinate.showErrorGLonlat = true;
	    				scope.coordinate.messageGLonlat = $translate.instant('GeoLocalizza.validate.longitude');
	    				return;
		    		}
					/* Verifica formato campo latitudine */
					if(!$.isNumeric(scope.coordinate.geoLat)){
		    			/** nascondo il loading */
						scope.isLoading = false;
						 
						/* add error formato non valido **/
	    				scope.coordinate.showErrorGLonlat = true;
	    				scope.coordinate.messageGLonlat = $translate.instant('GeoLocalizza.validate.latitude');
	    				return;
		    		}
		    		
					/* Crea la feature che ha per geometria le coordinate digitate. **/
					var feature = olFeatureService.createFeaturePoint(
							/* lon / lat */
							parseFloat(scope.coordinate.geoLon), parseFloat(scope.coordinate.geoLat),
							/* id feature **/
							appConstants.getParam("ol.ApplicationProperty").ID_FEATURE_GEO_LONLAT,
							/*  descrittore dello stile del marker */
							null,
							/* projection */
							scope.olMapAng.getOptions().getSourceProjection(), scope.olMapAng.getOptions().getDestProjection());
					
					/* elimino dal layer le feature **/
					scope.layGeoLonlat.getSource().clear();
					/* aggiungo la feature al layer **/
					scope.layGeoLonlat.getSource().addFeature(feature);
	    				
		    		/*
		    		 * Genero una transizione animata durante l'aggiornamento del centro della mappa.
		    		 */
					var pan = ol.animation.pan({
						/* The duration of the animation in milliseconds. Default is 1000. **/
						duration: 2000,
						/* The location to start panning from, typically map.getView().getCenter(). **/
						source: scope.olMapAng.getView().getCenter()
		    		});
					/*
					 * Aggiungo l'animazione che deve essere richiamata prima del rendering(prima di aggiornare la visualizzazione della mappa). 
					 */
					scope.olMapAng.beforeRender(pan);
					
					/* nascondo il loading */
					scope.isLoading = false;
					
					/* Ottenere l'estensione delle features. */
					var extent = scope.layGeoLonlat.getSource().getExtent();
					
					/* Adatta la forma geometrica data o misura in base alla data dimensione mappa e di confine. **/
					scope.olMapAng.getView().fit(extent, scope.olMapAng.getSize(), {"maxZoom": 14});
					
					/*
					 * Forza il ricalcolo della dimensione della mappa
					 */
					scope.onResize();
			    }catch(e){
			    	log.error("localizzaGeoLonLat >> " + e);
			    	/* nascondo il loading */
			    	scope.isLoading = false;
			    }
	    	}// close localizzaGeoLonLat
		   	
	    }// close if hasCercaLonlat
	    	 
 /** ======================================================================================== **/
 /*  								  FUNZIONI X IL FORMATO WKT 							   */
 /** ======================================================================================== **/
	
	    if(scope.config.editToolbar.enable && scope.config.editToolbar.hasWkt){
	    	/**
	    	 * Gestione reset campo Wkt.
	    	 */
	    	scope.clearFormatWktDraw = function() {
	    		/* remove error **/
    			scope.format.showErrorWkt = false;
				scope.format.messageWkt = "";
				
	    		/* svuoto il campo di ricerca **/
	    		scope.format.formatWktDraw = "";
	    	}
		   	
	    	/** 
	    	 * Al click del button viene richiamata una funzione che legge la stringa Wkt inserita e disegna la geometria su mappa
	    	 */
	    	scope.drawGeometryToWkt = function() {
	    		try{
	    			/* Mostra il loading */
	    			scope.isLoading = true;
	    			
	    			/* remove error **/
	    			scope.format.showErrorWkt = false;
    				scope.format.messageWkt = "";
    					
	    			if(!angular.isDefined(scope.format.formatWktDraw) || scope.format.formatWktDraw == ""){
	    				/* Rimuove il loading */
	    				scope.isLoading = false;
	    				
	    				/* add error campo abbligatorio **/
	    				scope.format.showErrorWkt = true;
	    				scope.format.messageWkt = $translate.instant('Validator.requiredField');
	    				return ;
					}
						 
	    			/* Ritorna la feature dalla string WKT. **/
	    			var feature = olFormatService.olReadFeatureToWkt(scope.format.formatWktDraw, scope.olMapAng.getOptions().getSourceProjection(), scope.olMapAng.getOptions().getDestProjection());
						 
	    			if(feature == null){
	    				/* Rimuove il loading */
	    				scope.isLoading = false;
							
	    				/* add error stringa wkt non valida **/
	    				scope.format.showErrorWkt = true;
	    				scope.format.messageWkt = $translate.instant('DrawFormat.btn.invalid.format.wkt');
	    				return ;
					}
						 
	    			/* controllo se il tipo della geometria è uno di quelli previsti come opzione della mappa **/
					if( $.inArray(feature.getGeometry().getType(), scope.olMapAng.getOptions().getGeometryType()) == -1 ){
						/* Rimuove il loading */
						scope.isLoading = false;
						
						/* add error tipo geometria non valido **/
						scope.format.showErrorWkt = true;
	    				scope.format.messageWkt = $translate.instant('DrawFormat.geometry.type.not.valid', {"tipo":scope.olMapAng.getOptions().getGeometryType().toString()});
						return ; 
					}
						
					/* svuoto il layer dalle feature **/
					scope.vector.getSource().clear();
					/* aggiungo la feature al layer **/
					scope.vector.getSource().addFeature(feature);
				    		
					/* Rimuove il loading */
					scope.isLoading = false;
						
					/*
					 * Genero una transizione animata durante l'aggiornamento del centro della mappa.
					 */
					var pan = ol.animation.pan({
						/* The duration of the animation in milliseconds. Default is 1000. **/
						duration: 2000,
						/* The location to start panning from, typically map.getView().getCenter(). **/
						source: scope.olMapAng.getView().getCenter()
				    });
					/*
					 * Aggiungo l'animazione che deve essere richiamata prima del rendering(prima di aggiornare la visualizzazione della mappa). 
					 */
				    scope.olMapAng.beforeRender(pan);
				    
				    /* Ottenere l'estensione delle features. */
				    var extent = scope.vector.getSource().getExtent();
				    		
				    /* Adatta la forma geometrica data o misura in base alla data dimensione mappa e di confine. **/
				    scope.olMapAng.getView().fit(extent, scope.olMapAng.getSize(), {"maxZoom": scope.config.zoom});
				    
				}catch(e){
					log.error("drawGeometryToWkt >> " + e);
					/* nascondo il loading */
					scope.isLoading = false;
			    }
			}// close drawGeometryToWkt
				
	    }// close if config.editToolbar.hasWkt
	  
 /** ======================================================================================== **/
 /*  								  FUNZIONI X IL FORMATO GEOJSON 						   */
 /** ======================================================================================== **/
			
	    if(scope.config.editToolbar.enable && scope.config.editToolbar.hasGeoJson){
	    	
	    	/**
	    	 * Gestione reset campo GeoJson
	    	 */
	    	scope.clearFormatGeoJsonDraw = function (){
	    		/* remove error **/
    			scope.format.showErrorGJson = false;
				scope.format.messageGJson = "";
	    		/* svuoto il campo di ricerca **/
	    		scope.format.formatGeoJsonDraw = "";
			}// close clearFormatGeoJsonDraw
				
	    	/** 
	    	 * Al click del button viene richiamata una funzione che legge la stringa GeoJson inserita e disegna la geometria su mappa
	    	 */
	    	scope.drawFormatGeoJson = function (){
	    		try{
	    			/** Mostra il loading */
	    			scope.isLoading = true;
	    			
	    			/* remove error **/
	    			scope.format.showErrorGJson = false;
					scope.format.messageGJson = ""; 
							
	    			if(!angular.isDefined(scope.format.formatGeoJsonDraw) || scope.format.formatGeoJsonDraw == ""){
	    				/** Rimuove il loading */
	    				scope.isLoading = false;
	    					
	    				/* add error campo abbligatorio **/
	    				scope.format.showErrorGJson = true;
	    				scope.format.messageGJson = $translate.instant('Validator.requiredField');
						return ;
					}
						 
	    			/** Ritorna la feature dalla string GeoJson. **/
	    			var feature = olFormatService.olReadFeatureToGeoJson(scope.format.formatGeoJsonDraw, scope.olMapAng.getOptions().getSourceProjection(), scope.olMapAng.getOptions().getDestProjection());
	    			
	    			if(feature == null){
	    				/** Rimuove il loading */
	    				scope.isLoading = false;
	    				
	    				/* add error campo abbligatorio **/
	    				scope.format.showErrorGJson = true;
	    				scope.format.messageGJson = $translate.instant('DrawFormat.btn.invalid.format.geojson');
	    				return ;
					}
						 
	    			/** controllo se il tipo della geometria è uno di quelli previsti come opzione della mappa **/
	    			if( $.inArray(feature.getGeometry().getType(), scope.olMapAng.getOptions().getGeometryType()) == -1 ){
	    				/** Rimuove il loading */
	    				scope.isLoading = false;
	    				
	    				/* add error campo abbligatorio **/
	    				scope.format.showErrorGJson = true;
	    				scope.format.messageGJson = $translate.instant('DrawFormat.geometry.type.not.valid', {"tipo":scope.olMapAng.getOptions().getGeometryType().toString()});
	    				return ; 
					}
						 
	    			/** svuoto il layer dalle feeature **/
	    			scope.vector.getSource().clear();
	    			/** aggiungo la feature al layer **/
	    			scope.vector.getSource().addFeature(feature);
					    		
	    			/** Rimuove il loading */
	    			scope.isLoading = false;
						
	    			/**
	    			 * Genero una transizione animata durante l'aggiornamento del centro della mappa.
	    			 */
	    			var pan = ol.animation.pan({
	    				/** The duration of the animation in milliseconds. Default is 1000. **/
	    				duration: 2000,
	    				/** The location to start panning from, typically map.getView().getCenter(). **/
	    				source: scope.olMapAng.getView().getCenter()
					});
	    			/**
	    			 * Aggiungo l'animazione che deve essere richiamata prima del rendering(prima di aggiornare la visualizzazione della mappa). 
	    			 */
	    			scope.olMapAng.beforeRender(pan);
	    			
	    			/** Ottenere l'estensione delle features. */
	    			var extent = scope.vector.getSource().getExtent();
	    			
	    			/** Adatta la forma geometrica data o misura in base alla data dimensione mappa e di confine. **/
	    			scope.olMapAng.getView().fit(extent, scope.olMapAng.getSize(), {"maxZoom": scope.config.zoom});
						
				}catch(e){
					log.error("drawFormatGeoJson >> " + e);
					/** nascondo il loading */
					scope.isLoading = false;
			    }
			}// close drawFormatGeoJson
				
	    }// close if config.editToolbar.hasGeoJson
	    	
 /** ======================================================================================== **/
 /*  										 FUNCTION PUBBLICHE								   */
 /** ======================================================================================== **/
	    		    	
	    /**
	     * Costruisce la geometria dell'anagrafica disegnata, tenendo conto se l'opzione "multi" è attiva o meno.
	     * 
	     * Comportamento della funzione:
	     * 	1. opzione "multi" non attiva: ritorna la geometria singola nel type in cui è stata disegnata.
	     * 	3. opzione "multi" attiva: compongo la geometry Multi... integrando insieme le geometrie delle singole feature disegnate.
	     */
	    scope.getGeometryDraw = function (features){
	    	/* */
			var geometry = null;
			
	    	if(!scope.config.editToolbar.multi){
	    		/* SINGLE GEOMETRY, ritorna la geometria singola nel type in cui è stata disegnata */
	    		
				/* */
				var temp = features[0].clone();
				
				/* Recupero la geometry e ne cambio la projection in quella del server  **/
				geometry = temp.getGeometry().transform(appConstants.getParam("Constants").DEST_PROJECTION, appConstants.getParam("Constants").SOURCE_PROJECTION);
						
				/* se la geometry è un Circle, la trasformo in poligono */
				if (geometry instanceof ol.geom.Circle) geometry = ol.geom.Polygon.fromCircle(geometry);
			}else{
				/* MULTI GEOMETRY, compongo la geometry Multi... integrando insieme le geometrie delle singole feature disegnate. */
				
				if($.inArray(appConstants.getParam("ol.geom.GeometryType").MULTI_POINT, scope.olMapAng.getOptions().getGeometryType()) != -1){
					/* instances Multi geometry */
					geometry = new ol.geom.MultiPoint();
				}//
			
				if($.inArray(appConstants.getParam("ol.geom.GeometryType").MULTI_LINE_STRING, scope.olMapAng.getOptions().getGeometryType()) != -1){
					/* instances Multi geometry */
					geometry = new ol.geom.MultiLineString();
				}//
				 
				if($.inArray(appConstants.getParam("ol.geom.GeometryType").MULTI_POLYGON, scope.olMapAng.getOptions().getGeometryType()) != -1){
					/* instances Multi geometry */
					geometry = new ol.geom.MultiPolygon();
				}//
				
				/* Ciclo le feature disegnate */
				angular.forEach(features, function(value, key) {
					/* */
					var temp = value.clone();
					
					/* Recupero la geometry e ne cambio la projection in quella del server  **/
					var geom = temp.getGeometry().transform(appConstants.getParam("Constants").DEST_PROJECTION, appConstants.getParam("Constants").SOURCE_PROJECTION);
					
					if (geom instanceof ol.geom.MultiPoint || geom instanceof ol.geom.MultiPolygon || geom instanceof ol.geom.MultiLineString){
						/* */
						if (geom instanceof ol.geom.MultiPoint) {
							/* */
							angular.forEach(geom.getPoints(), function(value, key) {
								/* Append the passed point to this MultiPoint. */
								geometry.appendPoint(value);
							});
						}
						/* */
						if (geom instanceof ol.geom.MultiLineString) {
							/* */
							angular.forEach(geom.getLineStrings(), function(value, key) {
								/* Append the passed linestring to this MultiLineString. */
								geometry.appendLineString(value);
							});
						}
						/* */
						if (geom instanceof ol.geom.MultiPolygon) {
							/* */
							angular.forEach(geom.getPolygons(), function(value, key) {
								/* Append the passed polygon to this MultiPolygon. */
								geometry.appendPolygon(value);
							});
						}
					}else{
						/* Append the passed geometry to this Multi... */
						if (geom instanceof ol.geom.Point) 		geometry.appendPoint(geom);
						if (geom instanceof ol.geom.LineString) geometry.appendLineString(geom);
						if (geom instanceof ol.geom.Polygon) 	geometry.appendPolygon(geom);
						if (geom instanceof ol.geom.Circle) 	geometry.appendPolygon(ol.geom.Polygon.fromCircle(geom));
					}
				});
			}// close else multi geometry
	    	
	    	return geometry;
	    }// close getGeometryDraw
	    
	    
	    scope.api = {
	    	/**
	    	 * Forza il ricalcolo della dimensione della mappa. Questo dovrebbe essere chiamato quando il codice di terze parti cambia la 
	    	 * dimensione della finestra in cui è disegnata la mappa.
	    	 */
	    	updateSize : function () {
	    		/**
	    		 * Forza il ricalcolo della dimensione della mappa
	    		 */
	    		scope.onResize();
	    	},
	    	/** 
	    	 * svuota la mappa da eventuali geometrie disegnate, disattiva tutti i controlli e svuota i campi dei diversi tool
	    	 */
	    	resetWidget : function () {
	    		/**
	    		 * Eliminazione geometria disegnata e disattivazione dei controlli
	    		 */
	    		scope.resetWidget();
	    	},
	    	/** 
	    	 * Ritorna il WKT della geometria disegnata, altrimenti null.
	    	 */
	    	geometryAsWkt : function () {
	    		
	    		if(scope.vector != null){
	    			/* mi prendo le features **/
	    			var features = scope.vector.getSource().getFeatures();
	    			
	    			/* controllo che ci sia almeno una feature da salvare **/
	    			if(features != null && features.length != 0){
	    				/**
	    			     * Costruisce la geometria dell'anagrafica disegnata, tenendo conto se l'opzione "multi" è attiva o meno.
	    			     * 
	    			     * Comportamento della funzione:
	    			     * 	1. opzione "multi" non attiva: ritorna la geometria singola nel type in cui è stata disegnata.
	    			     * 	3. opzione "multi" attiva: compongo la geometry Multi... integrando insieme le geometrie delle singole feature disegnate.
	    			     */
	    				var geometry = scope.getGeometryDraw(features);
	    				
	    				/** Return Rappresentazione in formato wkt della geometria **/
	    				return olFormatService.olWktTransorm(geometry);
	    			}else
	    			   /* Layer Vuoto, return null. **/
	    			   return null;
	    		}else
	    		   /* Layer is null, return null. **/
	    		   return null;
	    	},// close geometryAsWkt
	    	/** 
	    	 * Ritorna la geometry della geometria disegnata, altrimenti null.
	    	 */
	    	geometryAsGeom : function () {
	    		
	    		if(scope.vector != null){
	    			/* Mi prendo le features **/
	    			var features = scope.vector.getSource().getFeatures();
	    			
	    			/* controllo che ci siano feature da salvare */
	    			if(features != null && features.length != 0)
	    				/**
	    			     * Costruisce la geometria dell'anagrafica disegnata, tenendo conto se l'opzione "multi" è attiva o meno.
	    			     * 
	    			     * Comportamento della funzione:
	    			     * 	1. opzione "multi" non attiva: ritorna la geometria singola nel type in cui è stata disegnata.
	    			     * 	3. opzione "multi" attiva: compongo la geometry Multi... integrando insieme le geometrie delle singole feature disegnate.
	    			     */
	    				return scope.getGeometryDraw(features);
	    			else
	    			  /* Layer Vuoto, return null. **/
	    			  return null;
	    		}else
	    		   /* Layer is null, return null. **/
	    		   return null;
	    	},// close geometryAsGeom
	    	
	    	/**
	    	 * Abilita gli strumenti di edit della mappa e i vari tool di modo che la mappa sia editabile.
	    	 */
	    	enableWidget : function (){
		    	/** Se attivo, reset del componente che disegna la geometria a partire dalla stringa WKT */
		    	if (scope.config.editToolbar.enable && scope.config.editToolbar.hasWkt) {
		    		/* svuoto il campo di ricerca **/
		    		scope.format.formatWktDraw = "";
		    		/* chiudo il popup di help **/
		    		scope.wktPopover.isOpen = false;
		    	}
		    	
		    	/** Se attivo, reset del componente che disegna la geometria a partire dal strina GeoJson */
		    	if (scope.config.editToolbar.enable && scope.config.editToolbar.hasGeoJson) {
		    		/* svuoto il campo di ricerca **/
		    		scope.format.formatGeoJsonDraw = "";
		    		/* chiudo il popup di help **/
		    		scope.geojsonPopover.isOpen = false;
		    	}
		    		
		    	/** Se attivo, reset del componente dell albero  */
		    	if(scope.config.treeConfig.hasEntityTree){
		    		/* hide the popup. */
				    scope.closePopup();
				    /* Svuoto il layer dall'ultima feature disegnata. */
				    scope.vectorEntity.getSource().clear(true);
				    /* Elimino le feature eventualmente selezionate. */
				    if( scope.highlightsEntityInteraction != null ) scope.highlightsEntityInteraction.getFeatures().clear(true);
				    /* Elimino le feature eventualmente selezionate. */
				    if( scope.selectEntityInteraction != null ) 	scope.selectEntityInteraction.getFeatures().clear(true);
		    	}
	    		
	    		/* enable edit control **/
	    		scope.isDisableEditToolbar = false;
	    		
	    		/* Disabilito il button di "Undo" per Rimuovere l'ultimo punto della della feature disegnata */
		      	scope.isDisableUndo = true;
	    	},//close enableWidget
	    		
	    	/**
	    	 * Disabilita gli strumenti di edit della mappa e i vari tool di modo che la mappa sia navigabile in sola lettura.
	    	 */
	    	disableWidget : function (){
	    		/* Elimino le feature eventualmente selezionate. */
	    		if( scope.selectInteraction != null ) 	scope.selectInteraction.getFeatures().clear(true);
	  				
	    		/* disattivo i controlli **/
	    		if(scope.drawPointInteraction != undefined)   scope.drawPointInteraction.active = false;
	    		if(scope.drawLineInteraction != undefined)    scope.drawLineInteraction.active = false;
	    		if(scope.drawPolygonInteraction != undefined) scope.drawPolygonInteraction.active = false;
	    		if(scope.drawCircleInteraction != undefined)  scope.drawCircleInteraction.active = false;
	  				
	    		scope.selectInteraction.active = false;
		  			
	    		/* Disattivo l'evento. */
	    		scope.olMapAng.un('pointermove', pointerMoveHandler);
	    		/* Remove help tooltip */
	    		scope.removeHelpTooltip();
	    		/* unset sketch **/
	    		scope.ngSketchFeature = null;

	    		/* refresh mappa **/
	    		scope.onResize();
	  				
	    		/* box: wkt - GeoJson */
	    		if(scope.config.editToolbar.enable && (scope.config.editToolbar.hasWkt || scope.config.editToolbar.hasGeoJson)){
	    			scope.ngShowWidgetDraw = false;
	    		}
	    			
	    		/* Se attivo, chiudo le popup eventulamente aperte  */
		    	if(scope.config.treeConfig.hasEntityTree){
		    		/* hide the popup. */
				    scope.closePopup();
		    	}
		    	
	    		/* disable toolbar **/
	    		scope.isDisableEditToolbar = true;
	    		
	    		/* Disabilito il button di "Undo" per Rimuovere l'ultimo punto della della feature disegnata */
		      	scope.isDisableUndo = true;
	    	},// close disableWidget
	    	
	    	/** 
	    	 * Aggiunge alla mappa la feature costruita a partire dal WKT della geometria fornito come parametro.
	    	 * Questa funzione serve a visualizzare su mappa l'entità qualora si conosca già la gemetria(Es: caso di dettaglio entità)
	    	 */
	    	addGeometryAsWkt : function (wkt) {
	    			  			
	    		if(wkt != undefined && wkt != null){
	    			/** elimino dal layer le feature **/
	    			scope.vector.getSource().clear();
	    			
	    			/** Ritorna la feature dalla string WKT. **/
	    			var feature = olFormatService.olReadFeatureToWkt(wkt, scope.olMapAng.getOptions().getSourceProjection(), scope.olMapAng.getOptions().getDestProjection());
	    			
	    			if(feature != null){
	    				/** aggiungo la feature al layer **/
	    				scope.vector.getSource().addFeature(feature);
				    		
				    	/**
				    	 * Genero una transizione animata durante l'aggiornamento del centro della mappa.
				    	 */
	    				var pan = ol.animation.pan({
	    					/** The duration of the animation in milliseconds. Default is 1000. **/
	    					duration: 2000,
	    					/** The location to start panning from, typically map.getView().getCenter(). **/
	    					source: scope.olMapAng.getView().getCenter()
					    });
	    				/**
	    				 * Aggiungo l'animazione che deve essere richiamata prima del rendering(prima di aggiornare la visualizzazione della mappa). 
	    				 */
	    				scope.olMapAng.beforeRender(pan);
					    		
	    				/** Ottenere l'estensione delle features. */
	    				var extent = scope.vector.getSource().getExtent();
					    		
	    				/** Adatta la forma geometrica data o misura in base alla data dimensione mappa e di confine. **/
	    				scope.olMapAng.getView().fit(extent, scope.olMapAng.getSize()[0] == 0 ? appConstants.getParam("ol.ApplicationProperty").SIZE_MAP : scope.olMapAng.getSize(), {"maxZoom": scope.config.zoom});
	    			}else
	    			   /* feature non correttamente creata */
	    			   log.warn("addGeometryAsWkt >> feature is null.")
	    		}else
	    		   /* parametro in ingresso non fornito */
	    		   log.warn("addGeometryAsWkt >> parametro undefined o vuoto.");
	    	},// close addGeometryAsWkt
	    	
	    	/** 
	    	 * Aggiunge nella parte centrale della toolbar l'indirizzo che localizza la geometria. (SOLA LETTURA)
	    	 */
	    	setHeaderAddress: function (_indirizzo, _comune, _provincia) {
	    		/*
	    		 */
	    		scope.headerAddress = {visible: true, indirizzo: _indirizzo, provincia: _provincia, comune: _comune }
	    	},// close setHeaderAddress
	    	
	    	/** 
	    	 * Rimuove dalla toolbar la visualizzazione dell'indirizzo che localizza la geometria.
	    	 */
	    	clearHeaderAddress: function () {
	    		/*
	    		 */
	    		scope.headerAddress = {visible: false};
	    	}// close clearHeaderAddress
	    }// close api
	    	
 /** ======================================================================================== **/
 /*  								FUNCTION VALIDATION --> REQUIRED 						   */
 /** ======================================================================================== **/
	    	
	    /**
	     * Controllo se devo abilitare la validazione della geometria (instesa come obbligatoria)
	     */
	    if(scope.isRequired){
	    	/**
	    	 * Attivo il watch sulla funzione che restituisce la geometria disegnata
	    	 */
	    	scope.$watch(function() {
	    		return scope.api.geometryAsWkt();
			}, function(value) {
				if(angular.isUndefined(value) || value == null) 
					scope.ngModel = false;
			    else
			    	scope.ngModel = true;
			});
	    }
	 
 /** ======================================================================================== **/
 /*  										FUNCTION TREE ENTITY 							   */
 /** ======================================================================================== **/
	    		
			
	    /** Layer Tree Entity **/
	    if(scope.config.treeConfig.hasEntityTree) {
    			
	    	/**
	    	 * Apertura/chiusura albero dei layer
	    	 */
	    	scope.changeShowTreeEntity = function (){
	    		/* nascondo il box per disegnare */
	    		scope.ngShowWidgetDraw = false;
	    		/* nascondo il box per lo zoom */
	    		scope.ngShowWidgetZoom = false;
	    		/* */
	    		scope.ngShowTreeEntity = !scope.ngShowTreeEntity;
			}
				
	    	/**
	    	 * Add a click handler to hide the popup.
	    	 */
	    	scope.closePopup = function() {
	    		/**
	    		 * Set the position for this overlay. If the position is undefined the overlay is hidden.
	    		 */
	    		scope.overlay.setPosition(undefined);
		    		
	    		return false;
		    }// close closePopup
	    	
	    	/**
	    	 * Funziona richiamata al click del check per l'attivazione e la disattivazione della visibilità
	    	 * del layer delle anagrafiche.
	    	 */
	    	scope.checkVectorEntity = function (){
	    		if(!scope.vectorEntity.visible){
	    			/**
	    			 * Add a click handler to hide the popup.
	    			 */
	    			scope.closePopup();
	    			/** Elimino le feature eventualmente selezionate. */
	    			if( scope.selectEntityInteraction != null ) 	scope.selectEntityInteraction.getFeatures().clear(true);
	    			/** Elimino le feature eventualmente selezionate. */
	    			if( scope.highlightsEntityInteraction != null ) scope.highlightsEntityInteraction.getFeatures().clear(true);
		    	}
		    }// close checkVectorEntity
		    	
    	}// close if hasEntityTree
    		
  /** ======================================================================================== **/
	   	 	    	
	    /* segnalo che ho terminato di disegnare la mappa */
	   	scope.endRender = true;
	},
    controller: ["$scope", "$rootScope", function($scope, $rootScope) {
        /**
         * Inizializzazione interfaccia
         */
    	/** End startup mappa inizializzato a false **/
    	$scope.endRender = false;
	    	
    	/** Aggiungo allo scope della direttiva il language impostato nel $rootScope */
    	$scope.language = $rootScope.language;
    	
    	/** Feature disegnata dall'interaction. */
    	$scope.ngSketchFeature;
    	/** help tooltip element. */
    	$scope.helpTooltipElement = null;
    	/** Overlay per mostrare l' help messages. */
    	$scope.helpTooltip;
	    	
    	/** Il messaggio da visualizzare quando l'utente è in procinto di iniziare a disegnare. */
    	$scope.startMsg = $translate.instant("OpenLayers.olMeasure.helpMsg");
    	/** Messaggio da mostrare dopo che il primo punto di una linea viene disegnato. */
    	$scope.continueLinestringMsg = $translate.instant("OpenLayers.olMeasure.continueLinestringMsg");
    	/** Messaggio da mostrare dopo che il primo punto di un poligono viene disegnato. */
    	$scope.continuePolygonMsg = $translate.instant("OpenLayers.olMeasure.continuePolygonMsg");
	    /** Messaggio da mostrare dopo che il primo punto viene disegnato. */
    	$scope.continueCircleMsg = $translate.instant("OpenLayers.olMeasure.continueAzimutMsg");
			  
    	/** Per default i div degli strumenti di disegno sono nascosti, poi determino se e quali attivare in base alle configurazioni **/
    	$scope.enableDrawPoint = false;
    	$scope.enableDrawLine = false;
    	$scope.enableDrawPolygon = false;
    	$scope.enableDrawCircle = false;
    	
    	/** Inizializzo l'oggetto che gestisce i campi d'input del geocoding **/
    	$scope.geocoder = {
    		/* per deafult il loading dell'autocomplete è spento */
    		loadingLocations: false,
    		/* per default il DIV del messaggio "no results" è nascosto */
    		noResults: false,
    		/* per default il model del campo d'input dell'indirizzo è vuoto */
    		indirizzo: ""
	    };
	    	
    	/** Inizializzo l'oggetto che gestisce i campi d'input del tool delle coordinate **/
    	$scope.coordinate = {
	    	/* per default il model del campo d'input della longitudine è vuoto **/
	    	geoLon: "",
			/* per default il model del campo d'input della latitudine è vuoto **/
			geoLat: ""
    	};
    	
    	/** Inizializzo l'oggetto che gestisce i campi d'input del tool che disegna la geometria **/
    	$scope.format = {
	    	/* per default il model del campo d'input WKT è vuoto **/
    		formatWktDraw: "",
			/* per default il model del campo d'input GeoJson è vuoto **/
	    	formatGeoJsonDraw: ""
    	};
		
    	/** Inizializzo l'oggetto che gestisce la direttiva (ui.bootstrap.popover) per il wkt **/
    	$scope.wktPopover = {
    		/* per default il popup è chiuso **/
	    	isOpen: false,
	    	/* Label Help - Esempi WKT per le tipologie di geometrie gestite. */
	    	content: "POLYGON((9.202786010742392 45.497036820244396, <br />9.225445312500566 45.49414893704134, 9.217205566406765 45.48211449624514, <br />9.202786010742392 45.497036820244396))"
	    };
	    	
	    /** Inizializzo l'oggetto che gestisce la direttiva (ui.bootstrap.popover) per il GeoJson **/
    	$scope.geojsonPopover = {
	    	/* per default il popup è chiuso **/
	    	isOpen: false,
	    	/* Url del template - Esempi GeoJson per le tipologie di geometrie gestite. (Versione a tab) */
	    	content: appConstants.getParam("Constants").ContextPath + "page/template/mappa/GeoJsonHelp.jsp"
	    };
    	
    	/** Per default il DIV dell'albero dell'entity è chiuso. */
    	$scope.ngShowTreeEntity = false;
    	
    	/** Per default la toolbar dell'edit è disabilitata */
    	$scope.isDisableEditToolbar = false;
    	
    	/** Per deafult Disabilito il button di "Undo" per Rimuovere l'ultimo punto della feature disegnata */
      	$scope.isDisableUndo = true;
    	
 /** ======================================================================================== **/
 /*  											MAPPA										   */
 /** ======================================================================================== **/
        	        	        		
    	/**
    	 * Inizializzo l'oggetto contenente le impostazioni di configurazione della mappa.
    	 */
        $scope.olMapConfiguration = {
        	/* La projection con la quale l'entità sono gestite. **/
        	sourceProjection: appConstants.getParam("Constants").SOURCE_PROJECTION,
        	/* La projection con la quale l'entità sono disegnate in mappa. **/
        	destProjection: appConstants.getParam("Constants").DEST_PROJECTION,
        	/* Identificativo dell'elemento (div) in cui disegnare la mappa **/
        	targetMap: "mapAng",
        	/* Opzione per mostrare tutti gli attributi associati con le fonti di livello nella mappa. **/
        	enableAttribution: true,
        	/* Opzione per abilitare lo zoom in e lo zoom out. **/
			enableZoom: true,
			/* Opzione che fornisce un pulsante per attivare o disattivare la mappa in modalità a schermo intero. **/
			enableFullscreen: false,
			/* Un controllo per mostrare le coordinate 2D del cursore del mouse. **/
			enableMousePosition: true,
			/* Un controllo pulsante che, se premuto, cambia la visualizzazione della mappa in misura specifica. **/
			enableZoomToExtent: true,
			/*
			 * Identificativo dell'elemento da visualizzare a schermo intero. Quando non è previsto, sarà l'elemento che contiene la mappa viewport 
			 * ad essere visualizzato a schermo intero. 
			 */
			fullscreenSourceId: null,
			/*
			 * Identificativo dell'elemento HTML in cui openalyer inserirà i controlli che la libreria mette a disposizione. 
			 * (Es: zoomExtent, fuulscreen, 3D)
			 */
			controlTargetId: null,
			/*
			 * Determina se aggiungere ai controlli di Openlayer oltre l'icona, già prevista, anche una label testuale.
			 * (Es: zoomExtent, fullscreen, 3D, geoLocate, measureLength, measureArea, measureAzimut )
			 */
			advancedControlHasLabel: false,
			/* 
			 * Il controllo LayerSwitcher visualizza una tabella di contenuti per la mappa. In questo modo l'utente può per i layer di Base passare da un
			 * BaseLayers ad un'altro.
			 * Mentre, per i layer non di base, mostrare o nascondere i livelli e consentirne il riordino. 
			 * Per impostazione predefinita, lo switcher è mostrato minimizzato sul bordo destro della mappa, l'utente può espandere cliccando sulla maniglia.
			 */
			enableLayerSwitcher: false,
			/* Un controllo per disegnare la geometria di punti, linestring e poligoni sulla mappa **/
			enableDrawGeometry: true,
        	/* Array contenente le tipologie di geometrie che si possono disegnare e modificare sulla mappa **/
        	geometryType: $scope.config.editToolbar.geometryType       			
        };
        	
        /** 
         * Costruisco la mappa dalle configurazioni fornite di cui sopra.
         */
        var olMaps = olBuildService.buildMapToOptions($scope.olMapConfiguration);
        /**
         * Add instance to scope
         */
        $scope.olMapAng = olMaps.getMap2DInstance();
    		
         
 /** ======================================================================================= **/
 /*  											CONTROLLI									  */
 /** ======================================================================================= **/
    		 
        /** 
         * Aggiungo il controllo di openlayer che, se premuto, visualizza una tabella di contenuti per la mappa. In questo modo l'utente può per i 
         * layer di Base passare da un BaseLayers ad un'altro.
		 * Mentre, per i layer non di base, mostrare o nascondere i livelli e consentirne il riordino. 
		 * Per impostazione predefinita, lo switcher è mostrato minimizzato sul bordo destro della mappa, l'utente può espandere cliccando sulla 
		 * maniglia.
         */
        var layerSwitcher = new mycontrol.LayerSwitcher({
			/* Text label to use for the button tip. Default is "Legend" **/
			tipLabel: $translate.instant('OpenLayers.olSwitcher.tipLabel'),
			/* Testo dell'etichetta da utilizzare per identificare i layer di base. Il valore predefinito è 'Base Layer'.*/
			baseLabel: $translate.instant('OpenLayers.olSwitcher.baseLabel'),
			/* Testo dell'etichetta da utilizzare per identificare i layer non di base. Il valore predefinito è 'Overlay'. */
			overlayLabel: $translate.instant('OpenLayers.olSwitcher.overlayLabel'),
			/*  Se nel layer panel dovrebbero essere gestiti anche i layer non di base. Predefinito true. */
			hasOverlay: false
		});
        $scope.olMapAng.addControl(layerSwitcher);
        
        /** 
         * Controllo se l'opzione "editToolbar.enable" è attiva, se si determino quali strumenti di disegno attivare in base alle configurazioni 
         **/
        if($scope.config.editToolbar.enable){
        	
	        if($.inArray(appConstants.getParam("ol.interaction.GeometryType").POINT, $scope.olMapConfiguration.geometryType) != -1){
	        	/** Mostro il div del controllo **/
	        	$scope.enableDrawPoint = true;
	        	/** 
	        	 * Aggiungo il controllo di openlayer che, se premuto, viene attivato lo strumento per disegnare su mappa
	        	 * la geometria di un punto.
	        	 */
	        	$scope.drawPointControl = olControlService.createDrawPointControl("ol-draw-point-small", "fa-m-point-small", true);
	    	}// close Point
	
	        if($.inArray(appConstants.getParam("ol.interaction.GeometryType").LINE_STRING, $scope.olMapConfiguration.geometryType) != -1){
	        	/** Mostro il div del controllo **/
	        	$scope.enableDrawLine = true;
	        	/** 
		    	 * Aggiungo il controllo di openlayer che, se premuto, viene attivato lo strumento per disegnare su mappa
		    	 * la geometria di una linea.
		    	 */
	        	$scope.drawLineControl = olControlService.createDrawLineStringControl("ol-draw-linestring-small", "fa-m-linestring-small", true);
	    	}// close line
	    		
	        if($.inArray(appConstants.getParam("ol.interaction.GeometryType").POLYGON, $scope.olMapConfiguration.geometryType) != -1){
	        	/** Mostro il div del controllo **/
	        	$scope.enableDrawPolygon = true;
	        	/** 
	        	 * Aggiungo il controllo di openlayer che, se premuto, viene attivato lo strumento per disegnare su mappa
	        	 * la geometria di un poligono.
	        	 */
	        	$scope.drawPolygonControl = olControlService.createDrawPolygonControl("ol-draw-polygon-small", "fa-m-polygon-small", true);
	    			
	    		/** Mostro il div del controllo **/
	        	$scope.enableDrawCircle = true;
	        	/** 
	        	 * Aggiungo il controllo di openlayer che, se premuto, viene attivato lo strumento per disegnare su mappa
	        	 * la geometria di un cerchio.
	        	 */
	        	$scope.drawCircleControl = olControlService.createDrawCircleControl("ol-draw-circle-small", "fa-m-circle-small", true);
	    	}// close circle
	    		
	        /** 
	         * Aggiungo il controllo di openlayer che, se premuto, viene attivato lo strumento di edit della geometria.
	         */
	        $scope.modifyControl = olControlService.createModifyFeatureControl("ol-draw-modify-small", "fa-m-modify-small");
	        /** 
	         * Aggiungo il controllo di openlayer che, se premuto, elimina la geometria disegnata.
	         */
	        $scope.cancelControl = olControlService.createCancelDrawControl("ol-draw-cancel-small", "fa-trash-o"); //fa-m-cancel-small
    	}// close enable edit
    
        /** Controllo se l'opzione "Layer Tree Entity" è attiva **/
        if($scope.config.treeConfig.hasEntityTree) {
        	
        	/**
        	 * Un controllo pulsante che, se premuto, attiva/disattiva la visualizzazione dell'albero dei layer 
        	 * Per stile di questo controllo utilizzare il selettore CSS .ol-layers.
        	 */
        	$scope.treeEntityControl = olControlService.createLayerTreeControl("ol-layers-small", "top");
    	
        	/**
        	 * treeIcon_all: Path dell'icona rappresentativa del layer che mostra le anagrafiche filtrate dalla ricerca, è disegnata alla 
        	 * 				 sinistra del check che attiva/disattiva la visibilita del layer stesso.
        	 */
        	$scope.treeIcon_all = appConstants.getParam("Constants").treeStyles[$scope.config.treeConfig.layerName];
        }// close if hasEntityTree
    		
        /** Controllo se l'opzione "Cerca Indirizzo" o "Cerca Lonlat" è attiva **/
        if($scope.config.hasCercaIndirizzo || $scope.config.hasCercaLonlat) {
    			
        	/**
			 * Un controllo pulsante che, se premuto, attiva/disattiva la visualizzazione del widget che permette di spostare la view della mappa
			 * su una zona precisa.
			 */
        	$scope.zoomHelpControl = olControlService.createBaseControl("ol-search-small", "<i class='fa fa-search'></i>", $translate.instant('GeoLocalizza.cercaWidget.tipLabel'), 'top');
    	}// close if 
    		
    	/** Controllo se l'opzione "Disegna Wkt" o "Disegna GeoJson" è attiva **/
    	if($scope.config.editToolbar.enable && ($scope.config.editToolbar.hasWkt || $scope.config.editToolbar.hasGeoJson)) {
    			
    		/**
    		 * Un controllo pulsante che, se premuto, attiva/disattiva la visualizzazione del widget che premette di disegnare la geometria
    		 * dell'entità fornendone la stringa WKT o GeoJson.
    		 */
    		$scope.drawHelpControl = olControlService.createBaseControl("ol-text-small", "<i class='fa fa-pencil' aria-hidden='true'></i><i class='fa fa-text-width' aria-hidden='true'></i>", $translate.instant('GeoLocalizza.drawWidget.tipLabel'), 'top');
    	}// close if 
    		
 /** ======================================================================================== **/
 /*  									  LAYER EDIT - Ecc...								   */
 /** ======================================================================================== **/
    		    		        		
    	/**
    	 * Ritorna il layer vector appositamente configurato per la visualizzazione su mappa delle feature prodotte dagli strumenti di disegno.
    	 */
    	$scope.vector = olLayerService.createLayerVectorToDrawFeature($scope.config.treeConfig.stylesel_m);
    	/**
    	 * Fornisce una funzione che aggiunge proprietà (utilizzando Object.defineProperty) al livello, rendendo possibile il controllo 
    	 * delle proprietà del Layer con ng-model.
    	 */
    	ngeoDecorateLayer($scope.vector);
    	/** add layer alla mappa **/
    	$scope.olMapAng.addLayer($scope.vector);
    		
    	/** Layer widget "Cerca Lon/lat */
    	if($scope.config.hasCercaLonlat){
    		/* Ritorna il layer vector appositamente per il "cerca lon/lat". */
    		$scope.layGeoLonlat = olLayerService.createLayerVector(
    				appConstants.getParam("ol.ApplicationProperty").NAME_LAYER_GEO_LONLAT, olStyleService.createStyleGeoLonLat());
	    	/* add layer alla mappa **/
    		$scope.olMapAng.addLayer($scope.layGeoLonlat);
		}
			
    	/** Layer widget "Cerca Indirizzo" */
    	if($scope.config.hasCercaIndirizzo){
    		/* Ritorna il layer vector appositamente per il "cerca indirizzo". */
    		$scope.layGeocoder = olLayerService.createLayerVector(
			  			  appConstants.getParam("ol.ApplicationProperty").NAME_LAYER_GEOCODER_INDIRIZZO, olStyleService.createStyleGeoIndirizzo());
			/* add layer alla mappa **/
    		$scope.olMapAng.addLayer($scope.layGeocoder);
	    }
    	
    	/**
    	 * Controllo se devo creare e aggiungere alla mappa il layer per la visualizzazione delle anagrafiche.
    	 */
    	if($scope.config.treeConfig.hasEntityTree) {
    				
    		/* Definisco la fonte dei dati vettoriali */
    		var source = new ol.source.Vector({ 
    			features: [],
    			/**
    			 * The loader function used to load features, from a remote source for example. Note that the source will create and use 
    			 * an XHR feature loader when url is set.
    			 */
    			loader: function(extent, resolution, projection) {
							
    				/* loading ... */
    				$scope.isLoading = true;
    				
    				/* filtri di ricerca da mandare al servizio che ritorna le feature */
    				var params = $scope.config.treeConfig.requestData;
	    				/* linguaggio corrente **/
						params.locale = $scope.language;
						/* disattivo la paginazione */
						params.paginate = false;
					
					/**
					 * Controllo la strategy di caricamento da usare per il layer vector.
					 */
					if($scope.config.treeConfig.enableStrategyBbox){
						/*
						 * Get an ol.Extent rappresentante l'area della mappa caricata.
						 */
						var envelope = olFormatService.olProjTransformExtent(extent, $scope.olMapAng.getOptions().getDestProjection(), $scope.olMapAng.getOptions().getSourceProjection());
						/*
						 * Set come filtro di ricerca l'estensione della view della mappa.
						 */
						params.envelope = {
							/** the minimum x-coordinate */
							minx: envelope[0],
							/** the maximum x-coordinate */
							maxx: envelope[2],
							/** the minimum y-coordinate */
							miny: envelope[1],
							/** the maximum y-coordinate */
							maxy: envelope[3]
						}
					}//
						
    				/*  request object */
    				$http({
    					method: 'POST',
    					url: appConstants.getParam("Constants").ContextPath + $scope.config.treeConfig.url,
    					data: angular.toJson(params),
    					responseType: "json",
    					cache: false,
    				})
    				.then(function(response) {
    					if(response.data != null && response.data.success == true){
    						// dataProjection will be read from document
    						var features = 
    							olFormatService.olReadFeaturesToGeoJson(response.data.aaData, $scope.olMapAng.getOptions().getSourceProjection(), $scope.olMapAng.getOptions().getDestProjection());
    						
    						/* add features */
    						source.addFeatures(features);
    						
    						/* Controllo se applicare la logica di rimozione delle feture */
    						if($scope.config.treeConfig.excludeFeature != null){
    							/* Restituisce un array di feature che hanno la chiave di attributo data impostato al valore dato. */
    							var foundFea = source.getFeaturesByAttribute($scope.config.treeConfig.excludeFeature[0], $scope.config.treeConfig.excludeFeature[1]);
    							
    							/* controllo se è stata trovata una feature con attributo uguale a quello fornito, se si le rimuovo */
    							if(foundFea != null)
    								for(var i = 0; i<foundFea.length; i++) {source.removeFeature(foundFea[i])};
    						}
						}else
							/* add features vuota */
							source.addFeatures([]);
								
						/* spengo loading ... */
    					$scope.isLoading = false;
    				}, 
    				function errorCallback(response) {
    					/* add features vuota */
    					source.addFeatures([]);
    					/* spengo loading ... */
    					$scope.isLoading = false;
    					//
    					log.error("WidgetMapAng : ricerca entita' ---> " + ((angular.isDefined(response) && response != null ) ? angular.toJson(response) : response));
    				});
    			},// close loader
    			/** Determina la strategy di caricamento da usare per il layer vector che accoglie le fetaures risultanti dalla ricerca. **/
				strategy: ($scope.config.treeConfig.enableStrategyBbox) ? ol.loadingstrategy.bbox : ol.loadingstrategy.all,
    			/** **/
    			wrapX: false,
    			/**
    			 * By default, an RTree is used as spatial index. When features are removed and added frequently, and the total number of 
    			 * features is low, setting this to false may improve performance.
    			 */
    			useSpatialIndex: false
    		});
    				
    		/** */
    		$scope.vectorEntity = new ol.layer.Vector({
    			/* **/
    			source: source,
    			/* The feature style. ol.style.Style **/
				style: function (feature){
					return TemplateStyles.findStyleByCodeLayer($scope.olMapAng, feature);
				},
				/* Nome del layer **/
				name: $scope.config.treeConfig.layerName,
    			/* Visibility **/
    			visible: true
    		});
    				
    		/**
    		 * Fornisce una funzione che aggiunge proprietà (utilizzando Object.defineProperty) al livello, rendendo possibile il controllo 
    		 * delle proprietà del Layer con ng-model.
    		 */
    		ngeoDecorateLayer($scope.vectorEntity);
    		
    		/** add layer alla mappa **/
    		$scope.olMapAng.addLayer($scope.vectorEntity);
    		
    		/**
			 * Controllo se la strategy di caricamento da usare per il layer vector è la BBox, perchè in tal caso devo mettere
			 * in ascolto la mappa sull'evento "change:resolution".
			 */
			if($scope.config.treeConfig.enableStrategyBbox){
				/**
				 * Siccome la strategy bbox cachezza il layer per extent, accadrebbe che poi per extent già caricate, non rieffettua la chiamata 
				 * quindi la forzo io.
				 */
	    		$scope.olMapAng.getView().on('change:resolution', function(evt){
	    			$scope.vectorEntity.getSource().clear(true);
	    		});
			}
    	}// close if hasEntityTree
    		
 /** ======================================================================================== **/
 /*  									 	INTERACTION POINT								   */
 /** ======================================================================================== **/
    		   
    	if($scope.config.editToolbar.enable && $.inArray(appConstants.getParam("ol.interaction.GeometryType").POINT, $scope.olMapConfiguration.geometryType) != -1){
    			
    		/**
    		 * Ritorna lo strumento di disegno appositamente configurato per tracciare punti su mappa.
    		 */
    		$scope.drawPointInteraction = olInteractionService.createDrawInteraction($scope.vector.getSource(), appConstants.getParam("ol.interaction.GeometryType").POINT);
    		/**
    		 * NOTA "ngeoDecorateInteraction":
    		 *   Fornisce una funzione che aggiunge una proprietà "active" (usando Object.defineProperty) ad una interaction, rendendo possibile 
    		 *   l'uso di ng-model per attivare / disattivare interazioni.
    		 */
    		ngeoDecorateInteraction($scope.drawPointInteraction);
    		/**
    		 * Aggiungo l'interaction alla mappa
    		 */
    		$scope.olMapAng.addInteraction($scope.drawPointInteraction);
    		/**
    		 * Provides a service to manage the activation of ngeo.toolActivate objects.
    		 * Each tool must be registered before using it.
    		 * Uno strumento verrà registrato in un gruppo identificato da un nome. Una volta registrato uno strumento può essere attivato
    		 * e disattivato. Quando si attiva uno strumento, tutti gli altri strumenti dello stesso gruppo saranno disattivati.
    		 */
    		var drawPointTool = new ngeo.ToolActivate($scope.drawPointInteraction, 'active');
    		ngeoToolActivateMgr.registerTool('mapTools', drawPointTool);
    			
    	}// close point

 /** ======================================================================================== **/
 /*  									 INTERACTION LINE_STRING							   */
 /** ======================================================================================== **/
    		    		   
    	if($scope.config.editToolbar.enable && $.inArray(appConstants.getParam("ol.interaction.GeometryType").LINE_STRING, $scope.olMapConfiguration.geometryType) != -1){
    		
    		/**
    		 * Ritorna lo strumento di disegno appositamente configurato per tracciare linee su mappa.
    		 */
    		$scope.drawLineInteraction = olInteractionService.createDrawInteraction($scope.vector.getSource(), appConstants.getParam("ol.interaction.GeometryType").LINE_STRING);
    		/**
    		 * NOTA "ngeoDecorateInteraction":
    		 *   Fornisce una funzione che aggiunge una proprietà "active" (usando Object.defineProperty) ad una interaction, rendendo possibile 
    		 *   l'uso di ng-model per attivare / disattivare interazioni.
    		 */
    		ngeoDecorateInteraction($scope.drawLineInteraction);
    		/**
    		 * Aggiungo l'interaction alla mappa
    		 */
    		$scope.olMapAng.addInteraction($scope.drawLineInteraction);
    		/**
    		 * Provides a service to manage the activation of ngeo.toolActivate objects.
    		 * Each tool must be registered before using it.
    		 * Uno strumento verrà registrato in un gruppo identificato da un nome. Una volta registrato uno strumento può essere attivato
    		 * e disattivato. Quando si attiva uno strumento, tutti gli altri strumenti dello stesso gruppo saranno disattivati.
    		 */
    		var drawLineTool = new ngeo.ToolActivate($scope.drawLineInteraction, 'active');
    		ngeoToolActivateMgr.registerTool('mapTools', drawLineTool);
    		
    	}// close line
    		    		
 /** ======================================================================================== **/
 /*  									 INTERACTION DRAW POLYGON							   */
 /** ======================================================================================== **/
    		  
    	if($scope.config.editToolbar.enable && $.inArray(appConstants.getParam("ol.interaction.GeometryType").POLYGON, $scope.olMapConfiguration.geometryType) != -1){
    		
    		/**
    		 * Ritorna lo strumento di disegno appositamente configurato per tracciare poligoni su mappa.
    		 */
    		$scope.drawPolygonInteraction = olInteractionService.createDrawInteraction($scope.vector.getSource(), appConstants.getParam("ol.interaction.GeometryType").POLYGON);
    		/**
    		 * NOTA "ngeoDecorateInteraction":
    		 *   Fornisce una funzione che aggiunge una proprietà "active" (usando Object.defineProperty) ad una interaction, rendendo possibile 
    		 *   l'uso di ng-model per attivare / disattivare interazioni.
    		 */
    		ngeoDecorateInteraction($scope.drawPolygonInteraction);
    		/**
    		 * Aggiungo l'interaction alla mappa
    		 */
    		$scope.olMapAng.addInteraction($scope.drawPolygonInteraction);
    		/**
    		 * Provides a service to manage the activation of ngeo.toolActivate objects.
    		 * Each tool must be registered before using it.
    		 * Uno strumento verrà registrato in un gruppo identificato da un nome. Una volta registrato uno strumento può essere attivato
    		 * e disattivato. Quando si attiva uno strumento, tutti gli altri strumenti dello stesso gruppo saranno disattivati.
    		 */
    		var drawPolygonTool = new ngeo.ToolActivate($scope.drawPolygonInteraction, 'active');
    		ngeoToolActivateMgr.registerTool('mapTools', drawPolygonTool);
    			
    	}// close polygon
 
 /** ======================================================================================== **/
 /*  										INTERACTION	DRAW CIRCLE							   */
 /** ======================================================================================== **/
    		
    	if($scope.config.editToolbar.enable && $.inArray(appConstants.getParam("ol.interaction.GeometryType").POLYGON, $scope.olMapConfiguration.geometryType) != -1){
    		
    		/**
    		 * Ritorna lo strumento di disegno appositamente configurato per tracciare cerchi su mappa.
    		 */
    		$scope.drawCircleInteraction = olInteractionService.createDrawInteraction($scope.vector.getSource(), appConstants.getParam("ol.interaction.GeometryType").CIRCLE);
    		/**
    		 * NOTA "ngeoDecorateInteraction":
    		 *   Fornisce una funzione che aggiunge una proprietà "active" (usando Object.defineProperty) ad una interaction, rendendo possibile 
    		 *   l'uso di ng-model per attivare / disattivare interazioni.
    		 */
    		ngeoDecorateInteraction($scope.drawCircleInteraction);
    		/**
    		 * Aggiungo l'interaction alla mappa
    		 */
    		$scope.olMapAng.addInteraction($scope.drawCircleInteraction);
    		/**
    		 * Provides a service to manage the activation of ngeo.toolActivate objects.
    		 * Each tool must be registered before using it.
    		 * Uno strumento verrà registrato in un gruppo identificato da un nome. Una volta registrato uno strumento può essere attivato
    		 * e disattivato. Quando si attiva uno strumento, tutti gli altri strumenti dello stesso gruppo saranno disattivati.
    		 */
    		var drawCircleTool = new ngeo.ToolActivate($scope.drawCircleInteraction, 'active');
    		ngeoToolActivateMgr.registerTool('mapTools', drawCircleTool);
    		
    	}// close circle
    		
 /** ======================================================================================== **/
 /*  									INTERACTION	SELECT MODIFY							   */
 /** ======================================================================================== **/
    		    		    
    	/**
    	 * Ritorna lo strumento che gestisce la selezione dei dati vettoriali.
    	 */
    	$scope.selectInteraction = olInteractionService.createSelectDrawInteraction($scope.vector);

 /** ======================================================================================== **/
 /*  										INTERACTION TRANSLATE							   */
 /** ======================================================================================== **/
    	    		    		    
    	/**
    	 * Interaction for translating (moving) features.
    	 */
    	var translate = new ol.interaction.Translate({
    		/*
    		 * Solo features contenute in questa collezione saranno in grado di essere translate. Se non specificato, tutte le funzioni sulla 
    		 * mappa saranno in grado di essere translate.
    		 */
            features: $scope.selectInteraction.getFeatures()
    	});
    	/**
    	 * active interacion
    	 */
    	translate.setActive(true);
    	/**
    	 * Add interaction to map
    	 */
    	$scope.olMapAng.addInteraction(translate);
    	
 /** ======================================================================================== **/
 /*  										INTERACTION MODIFY		   						   */
 /** ======================================================================================== **/
    	       	
    	/**
    	 * Ritorna lo strumento di disegno appositamente configurato per tracciare cerchi su mappa.
    	 */
    	$scope.modifyInteraction = olInteractionService.createModifyInteraction($scope.selectInteraction);
    	$scope.modifyInteraction.setActive(true);
    	/**
    	 * NOTA "ngeoDecorateInteraction":
    	 *   Fornisce una funzione che aggiunge una proprietà "active" (usando Object.defineProperty) ad una interaction, rendendo possibile 
    	 *   l'uso di ng-model per attivare / disattivare interazioni.
    	 */
    	ngeoDecorateInteraction($scope.selectInteraction);
    	/**
    	 * Provides a service to manage the activation of ngeo.toolActivate objects.
    	 * Each tool must be registered before using it.
    	 * Uno strumento verrà registrato in un gruppo identificato da un nome. Una volta registrato uno strumento può essere attivato
    	 * e disattivato. Quando si attiva uno strumento, tutti gli altri strumenti dello stesso gruppo saranno disattivati.
    	 */
    	var modifyTool = new ngeo.ToolActivate($scope.selectInteraction, 'active');
    	ngeoToolActivateMgr.registerTool('mapTools', modifyTool);
 
 /** ======================================================================================== **/
 /*  											INTERACTION SNAP							   */
 /** ======================================================================================== **/
    	    
        /**
         * The snap interaction must be added after the Modify and Draw interactions
         * in order for its map browser event handlers to be fired first. Its handlers
         * are responsible of doing the snapping.
         * 
         * L'interaction SNAP deve essere aggiunto dopo la interaction di Modifica e Draw.
         * In modo che i suoi gestori di eventi mappa browser siano catturati prima. 
		 * I suoi gestori sono responsabili di fare lo scatto.
         */
        var snap = new ol.interaction.Snap({
        	/*
        	 * Snap to features from this source. Either this option or features should be provided
        	 */	
        	source: $scope.vector.getSource()
        });
        /**
    	 * active interacion
    	 */
        snap.setActive(true);
        /**
    	 * Add interaction to map
    	 */
        $scope.olMapAng.addInteraction(snap);
        
 /** ======================================================================================== **/
 /*  									 	FEATURE - OPEN POPUP							   */
 /** ======================================================================================== **/
    		
    	/**
    	 * Verifico se è attiva l'opzione hasEntityTree, in tal caso inizializzo e configuro l'oggetto ol.Overlay
    	 * di openlayers.
    	 */
    	if($scope.config.treeConfig.hasEntityTree){
    		/* popup template */
    		$scope.element = angular.element(
    				"<div class='ol-popup'>" +
    					"<span class='ol-popup-closer' ng-click='closePopup()'></span>" +
    					"<div class='popup-content' ng-cloak translate-cloak ></div>" +
	    					"<div class='popup_button'>" +
	    						"<p class='inline'><strong>{{'MappaAnag.entity.vaiAllaVisualizzazione' | translate}}</strong></p>" +
	    						"<div class='pull-right'>"+
	    							"<button type='button' class='btn-trasp' title=\"{{'MappaAnag.entity.cambiaAnagrafica' | translate}}\" " +
	    								"ng-click=\"config.treeConfig.broadcastFunction(properties)\" ><i class='fa fa-arrow-right'></i>" +
	    							"</button>" + 
	    						"</div>" +
		    				"</div>" +
	    				"</div>" +
	    			"</div>" );
	    		    		
    		/**
    		 * Un elemento da visualizzare sulla mappa e collegata a una singola posizione sulla mappa. 
    		 * Come ol.control.Control, overlay sono i widget visibili. A differenza dei controlli, non sono in una posizione fissa sullo 
    		 * schermo, ma sono legati a coordinate geografiche, così lo scorrimento della mappa muoverà l'overlay ma non un controllo.
    		 */
    		$scope.overlay = new ol.Overlay({
    			/* The overlay element. */
    			element: $scope.element[0],
    			/*
    			 * Offsets in pixels used when positioning the overlay. The fist element in the array is the horizontal offset. 
    			 * A positive value shifts the overlay right. The second element in the array is the vertical offset. 
    			 * A positive value shifts the overlay down. Default is [0, 0].
	    		 */
//	    	    offset: 
    			/*
    			 * Defines how the overlay is actually positioned with respect to its position property. 
    			 * Possible values are 'bottom-left', 'bottom-center', 'bottom-right', 'center-left', 'center-center', 'center-right', 'top-left', 
    			 * 'top-center', and 'top-right'. Default is 'top-left'.
    			 */
    			positioning: 'top-center',
    			/*
    			 * Whether event propagation to the map viewport should be stopped. Default is true. 
    			 * If true the overlay is placed in the same container as that of the controls (CSS class name ol-overlaycontainer-stopevent); 
    			 * if false it is placed in the container with CSS class name ol-overlaycontainer.
    			 */
    			stopEvent: true,
    			/*
    			 * if set to true the map is panned when calling setPosition, so that the overlay is entirely visible in the current viewport. 
    			 * The default is false.
    			 */
    			autoPan: true,
    			/*
    			 * The options used to create a ol.animation.pan animation. This animation is only used when autoPan is enabled. 
    			 * By default the default options for ol.animation.pan are used. If set to null the panning is not animated.
    			 */
    			autoPanAnimation: {
	    			/* The duration of the animation in milliseconds. Default is 1000. **/
    				duration: 250,
    				/* Maintain a constant speed over time.**/
	    			easing: ol.easing.linear
	    		},
	    		/* The margin (in pixels) between the overlay and the borders of the map when autopanning. The default is 20. */
	    		autoPanMargin: 20
	    	});
	    		
	    	/* Add the given overlay to the map.**/
	    	$scope.olMapAng.addOverlay($scope.overlay);
    	}// close if hasEntityTree 
    			
    		
 /** ======================================================================================== **/
 /*  								INTERACTION HIGHLIGHTS FEATURE							   */
 /** ======================================================================================== **/
    		
    	/**
    	 * Verifico se è attiva l'opzione hasEntityTree, in tal caso creo e aggiungo alla mappa l'interaction di highliths
    	 * sulla feature.
    	 */
    	if($scope.config.treeConfig.hasEntityTree){
    		/*
    		 * Style for the selected features
    		 */
    		var styleHighlight = function (feature){
    			return TemplateStyles.findStyleHighlightSelectByCodeLayer($scope.olMapAng, feature);
    		};
    		
    		/* Ritorna lo strumento che gestisce l'highlights dei dati vettoriali. */
    		$scope.highlightsEntityInteraction = olInteractionService.createHighlightsFeatureInteraction(null, $scope.vectorEntity, true, styleHighlight);
	    	
    		/* Add the given interaction to the map. */
    		$scope.olMapAng.addInteraction($scope.highlightsEntityInteraction);
    	}
    		    		
    		
 /** ======================================================================================== **/
 /**  								 INTERACTION SELECT FEATURE								  **/
 /** ======================================================================================== **/
    		
    	/**
    	 * Controllo se devo creare e aggiungere alla mappa il layer delle anagrafiche.
		 */
    	if($scope.config.treeConfig.hasEntityTree) {
    		
    		/*
    		 * Style for the selected features
    		 */
    		var styleSelect = function (feature){
    			return TemplateStyles.findStyleHighlightSelectByCodeLayer($scope.olMapAng, feature);
    		};
    		
    		/* Ritorna lo strumento che gestisce la selezione dei dati vettoriali. */
    		$scope.selectEntityInteraction = olInteractionService.createSelectFeatureInteraction(null, $scope.vectorEntity, true, styleSelect);
    		
    		/* Add the given interaction to the map. */
    		$scope.olMapAng.addInteraction($scope.selectEntityInteraction); 
    		
    		/**
    		 * Listner in select event
    		 */
    		$scope.selectEntityInteraction.on('select', function(e) {
    			if(e.selected.length != 0){
    				/* e stata selezionata una feature nascondo la popup corrente */
    				$scope.overlay.setPosition(undefined);
    				/* svuoto la variabile di scope dove ho mantengo le informazioni sulla feature selezionata */
    				$scope.properties = null;
    				
    				/* recupero la feature selezionata */
    				var fea = e.selected[0];
    				/* recupero le coordinate del punto cliccato */
    				var coordinates = e.mapBrowserEvent.coordinate;
	    				
    				/* 
    				 * Dopodicchè in base alla geometria, cerco di determinare un punto centrale alla stessa da assegnare all'overlay
    				 * come la posizione in cui se deve aprire.
    				 * Se non rieso a determinarle usa la coppia di coordinate derivate dal click sulla mappa.
    				 */ 
    				if (fea.getGeometry() instanceof ol.geom.Point) 	 		coordinates = fea.getGeometry().getCoordinates();
    				if (fea.getGeometry() instanceof ol.geom.MultiPoint) 		coordinates = fea.getGeometry().getFirstCoordinate();
    				
    				if (fea.getGeometry() instanceof ol.geom.LineString) 		coordinates = fea.getGeometry().getFirstCoordinate();
    				if (fea.getGeometry() instanceof ol.geom.MultiLineString) 	coordinates = fea.getGeometry().getFirstCoordinate();
    				
    				if (fea.getGeometry() instanceof ol.geom.Polygon) 	 		coordinates = fea.getGeometry().getFirstCoordinate();
    				if (fea.getGeometry() instanceof ol.geom.MultiPolygon) 		coordinates = fea.getGeometry().getFirstCoordinate()
    				
    				if (fea.getGeometry() instanceof ol.geom.Circle) 	 		coordinates = fea.getGeometry().getCenter();
    				
    				/* recupero le proprieta della feature, le aggiungo allo scope di modo che siano accesibili dal template della popup **/
    				$scope.properties = fea.getProperties();
    				/* creo una copia del template di modo da non modificare l'originale */
    				var template = angular.copy($scope.config.treeConfig.templatePopup);
    				
    				/* scrivo all'interno del template della popup, il template dell'anagrafica */
    				$scope.element.find(".popup-content").html(template)
    				
    				/* compile code angular */
    				$compile($scope.element)($scope);
    				
    				/* mostro la popup settando la ccordinate dela posizione dell'overlay */
    				$scope.overlay.setPosition(coordinates);
	            }// close if e.selected.length != 0
    		});// cclose event on
    	}// close if hasEntityTree
    			       		
    }]	
  }
}]);
